循环链表---对象赋值的相关问题
- 问题引入
- 单向循环链表节点的定义:
1 public class CirNode<T> 2 { 3 public T Item { get; set; } 4 public CirNode<T> Next { get; set; } 5 6 public CirNode() 7 { 8 } 9 10 public CirNode(T item) 11 { 12 this.Item = item; 13 } 14 }
2.单向循环链表的模拟实现:
1 /// <summary> 2 /// 单向循环链表的模拟实现 3 /// </summary> 4 public class MyCircularLinkedList<T> 5 { 6 private int count; // 字段:记录数据元素个数 7 private CirNode<T> tail; // 字段:记录尾节点的指针 8 private CirNode<T> currentPrev; // 字段:使用前驱节点标识当前节点 9 10 // 属性:指示链表中元素的个数 11 public int Count 12 { 13 get 14 { 15 return this.count; 16 } 17 } 18 19 // 属性:指示当前节点中的元素值 20 public T CurrentItem 21 { 22 get 23 { 24 return this.currentPrev.Next.Item; 25 } 26 } 27 28 public MyCircularLinkedList() 29 { 30 this.count = 0; 31 this.tail = null; 32 } 33 34 public bool IsEmpty() 35 { 36 return this.tail == null; 37 } 38 39 // Method01:根据索引获取节点 40 private CirNode<T> GetNodeByIndex(int index) 41 { 42 if (index < 0 || index >= this.count) 43 { 44 throw new ArgumentOutOfRangeException("index", "索引超出范围"); 45 } 46 47 CirNode<T> tempNode = this.tail.Next; 48 for (int i = 0; i < index; i++) 49 { 50 tempNode = tempNode.Next; 51 } 52 53 return tempNode; 54 } 55 56 // Method02:在尾节点后插入新节点 57 public void Add(T value) 58 { 59 CirNode<T> newNode = new CirNode<T>(value); 60 if (this.tail == null) 61 { 62 // 如果链表当前为空则新元素既是尾头结点也是头结点 63 this.tail = newNode; 64 this.tail.Next = newNode; 65 this.currentPrev = newNode; 66 } 67 else 68 { 69 // 插入到链表末尾处 70 newNode.Next = this.tail.Next; 71 this.tail.Next = newNode; 72 // 改变当前节点 73 if (this.currentPrev == this.tail) 74 { 75 this.currentPrev = newNode; 76 } 77 // 重新指向新的尾节点 78 this.tail = newNode; 79 } 80 Console.WriteLine(this.currentPrev.Next.Item); 81 this.count++; 82 } 83 84 // Method03:移除当前所在节点 85 public void Remove() 86 { 87 if (this.tail == null) 88 { 89 throw new NullReferenceException("链表中没有任何元素"); 90 } 91 else if (this.count == 1) 92 { 93 // 只有一个元素时将两个指针置为空 94 this.tail = null; 95 this.currentPrev = null; 96 } 97 else 98 { 99 if (this.currentPrev.Next == this.tail) 100 { 101 // 当删除的是尾指针所指向的节点时 102 this.tail = this.currentPrev; 103 } 104 // 移除当前节点 105 this.currentPrev.Next = this.currentPrev.Next.Next; 106 } 107 108 this.count--; 109 } 110 111 // Method04:获取所有节点信息 112 public string GetAllNodes() 113 { 114 if (this.count == 0) 115 { 116 throw new NullReferenceException("链表中没有任何元素"); 117 } 118 else 119 { 120 CirNode<T> tempNode = this.tail.Next; 121 string result = string.Empty; 122 for (int i = 0; i < this.count; i++) 123 { 124 result += tempNode.Item + " "; 125 tempNode = tempNode.Next; 126 } 127 128 return result; 129 } 130 } 131 }
其中循环链表新节点的插入实现方法中,用了对象赋值给另一个对象:
1 public void Add(T value) 2 { 3 CirNode<T> newNode = new CirNode<T>(value); 4 if (this.tail == null) 5 { 6 // 如果链表当前为空则新元素既是尾头结点也是头结点 7 this.tail = newNode;//@1 8 this.tail.Next = newNode;//@2 9 this.currentPrev = newNode;//@3 10 } 11 else 12 { 13 // 插入到链表末尾处 14 newNode.Next = this.tail.Next; 15 this.tail.Next = newNode; 16 // 改变当前节点 17 if (this.currentPrev == this.tail) 18 { 19 this.currentPrev = newNode; 20 } 21 // 重新指向新的尾节点 22 this.tail = newNode; 23 } 24 Console.WriteLine(this.currentPrev.Next.Item); 25 this.count++; 26 }
- 问题原因
其中@1处,把新new的一个对象newNode赋值给this.tail,此时这两个对象引用的是同一个内存地址空间,newNode.Next=null,this.tail.Next也是为Null,而到@2这一步时,给this.tail.Next赋值为newNode时,同时也会对newNode进行操作既给newNode.Next赋值,因为这两个对象引用的是同一个地址空间。
- 问题引申
- 1.浅复制和深复制:
浅复制:
1 public class Test 2 { 3 public string A { get; set; } 4 public int B { get; set; } 5 public override string ToString() 6 { 7 return $"A:{A},B:{B}"; 8 } 9 } 10 static void Main(string[] args) 11 { 12 var list = new List<Test>() 13 { 14 new Test(){A="A1",B=1 }, 15 new Test(){ A="A2",B=2} 16 }; 17 var list_Copy = list.ToList(); 18 list_Copy[0].A = "这是修改后的值"; 19 foreach (var i in list) 20 { 21 Console.WriteLine(i); 22 } 23 Console.Read(); 24 }
执行结果:
由上图可以看出,这里与循环链表里面的插入方法中的@1是一样的,修改list_Copy的元素的属性值,list中的元素的属性也跟着变了。
深复制:
1 public class Test:ICloneable 2 { 3 public string A { get; set; } 4 public int B { get; set; } 5 6 public object Clone() 7 { 8 return this.MemberwiseClone(); 9 } 10 11 public override string ToString() 12 { 13 return $"A:{A},B:{B}"; 14 } 15 } 16 static void Main(string[] args) 17 { 18 var list = new List<Test>() 19 { 20 new Test(){A="A1",B=1 }, 21 new Test(){ A="A2",B=2} 22 }; 23 var list_Copy = new List<Test>(); 24 list.ForEach(x => list_Copy.Add(x.Clone() as Test)); 25 list_Copy[0].A = "这是修改后的值"; 26 foreach (var i in list) 27 { 28 Console.WriteLine(i); 29 } 30 Console.Read(); 31 }
运行结果:
可以看出,修改list_Copy的任何元素任何属性,都不会影响到list,但是list与list_Copy中的元素值是相同的,这就是深复制。
深复制还可以借用json:
1 public static void Copy<T>(T source, ref T destination) where T : class 2 { 3 string jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(source); 4 destination = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonStr); 5 }
- 2.LeetCode上相关的题目:
问题描述:
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
解决代码:
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * public int val; 5 * public ListNode next; 6 * public ListNode(int x) { val = x; } 7 * } 8 */ 9 public class Solution { 10 public ListNode AddTwoNumbers(ListNode l1, ListNode l2) { 11 ListNode result = new ListNode(0); 12 ListNode cursor = result; 13 int carrybit = 0; 14 while (l1 != null||l2!=null|| carrybit!=0) 15 { 16 int sum = (l1 == null ? 0 : l1.val) + (l2 == null ? 0 : l2.val) + carrybit; 17 carrybit = sum / 10; 18 ListNode sumNode = new ListNode(sum % 10); 19 cursor.next = sumNode; 20 cursor = sumNode; 21 l1 = (l1 == null ? null : l1.next); 22 l2 = l2 == null ? null : l2.next; 23 } 24 return result.next; 25 } 26 }
首先是定义了两个ListNode对象,由于直接把result赋值给cursor,所以两者引用的是同一个地址。在While循环中定义的sumNode的内存空间的地址每次都不一样,当把cursor.next赋值为sumNode时,同时也会对result.next进行赋值操作。最重要的一步是把sumNode赋值给了cursor,这时cursor不再指向result的地址,而是指向这一次的sumNode的地址,此时也就是变为result.next=cursor。
所以最后返回result.next就能把初始化的值0从链表中去掉。
代码对应的流程:
参考文章链接:
- https://www.cnblogs.com/edisonchou/p/4614934.html
- https://blog.csdn.net/lishuangquan1987/article/details/86085971

浙公网安备 33010602011771号