不同集合含有相同元素时不能使用链表
2010-05-11 09:30
127 查看
如果集合有重叠元素,比如总人口集合、男性集合、女性集合,那么对这三个集合的表示,要谨慎使用链表。如下图:
注意,上面图中,使用的是Add(Node),而非使用Add(Value),两者有重大区别,前者,三条链表类共同修改一个链表,内存占用少,但是集合一旦有重叠就会引起错乱,后者每Add(Value)一次,就会重新new一个新的结点(查看Add的方法就知道了,里面有一个new Node()的动作),于是就会形成三条独立的链表,互不相干,也不会出现上述错误,但是同一个对象就拥有了多个克隆体,多占用了不少内存,而且,如果对其中一个链表的某个node中的value进行修改的话,就必须需要考虑同时修改其他链表中的值相同的value对象,C#双链表提供了Find(value)函数,用于在链表中找到引用value(非值相等,而是引用相等)的Node,然后使用Remove(node)将该结点删除。由于每个value可能有多个克隆,为了保持一致性,修改某个集合中的某一value的属性时,还必须要修改其他集合中的相同值的value的属性。举个例子,比如要在三个集合中添加人,第一个是男的,第二个男的,第三个是女的,第四个是男的,分别输出三个集合的人数,然后把第一个人删除,再输出三个集合的人数,程序如下:
改进方法,使用三个顺序表来完成,这样对各自顺序表增加要素或者删除要素都不影响其他顺序表,因为顺序表基于数组,对于任何一个value,都有对应的若干引用,value没有链表那种链式结构,它们是靠数组的Index来获得的。更重更要的是,内存中,任何一个value只需要一个拷贝,而不需要多个拷贝,这样就节省了内存,而且对value的修改更加方便,只需要修改一次即可。
我们假设使用的是Add(node)方法添加链表,而非使用Add(value)方法。第一步,往All链表中添加一个男性,同时Male链表中也要加入该男性,第二步,往All链表中添加一个男性,同时Male链表也要加入该男性(重复了),第三步,往All链表加入一个女性,同时Female链表也加入该女性要素,此时,加入的女性成员同时也加入了Male链表中,造成错误。根本原因在于,链表的前后引用关系,三个链表类对其有三个引用,但是操作的确是统一链表。当集合重叠的时候,一定出错。但是要注意的是,这种“同一个结点加入不同链表”的添加方法,只有在自定义的链表泛型类中才能使用,C#的LinkedList<>是禁止向链表中加入一个已经属于其他链表的结点的,下面这段程序因为违法了这一规定而报错:
若使用自定义自定义链表类(可以加入属于另外一个链表的结点),按上面顺序加入这几个人会有什么后果呢?后果是,第一步,indi1加入了All链表和Male链表;第二步,在All链表尾部加入value是indi2的结点(此时indi2成为链表All和链表Male的尾结点),然后在Male链表尾部(尾部结点的value已经是indi2)再次加入这一结点(因为这个人是男的),这是就会产生这样一个后果:node2的next属性等于他自己,也就是形成了死循环,此时计算All和Male链表的长度,则陷入死循环,无法得出结果。程序如下:
示意图为:
改进方法,使用三个顺序表来完成,这样对各自顺序表增加要素或者删除要素都不影响其他顺序表,因为顺序表基于数组,对于任何一个value,都有对应的若干引用,value没有链表那种链式结构,它们是靠数组的Index来获得的。更重更要的是,内存中,任何一个value只需要一个拷贝,而不需要多个拷贝,这样就节省了内存,而且对value的修改更加方便,只需要修改一次即可。
注意,上面图中,使用的是Add(Node),而非使用Add(Value),两者有重大区别,前者,三条链表类共同修改一个链表,内存占用少,但是集合一旦有重叠就会引起错乱,后者每Add(Value)一次,就会重新new一个新的结点(查看Add的方法就知道了,里面有一个new Node()的动作),于是就会形成三条独立的链表,互不相干,也不会出现上述错误,但是同一个对象就拥有了多个克隆体,多占用了不少内存,而且,如果对其中一个链表的某个node中的value进行修改的话,就必须需要考虑同时修改其他链表中的值相同的value对象,C#双链表提供了Find(value)函数,用于在链表中找到引用value(非值相等,而是引用相等)的Node,然后使用Remove(node)将该结点删除。由于每个value可能有多个克隆,为了保持一致性,修改某个集合中的某一value的属性时,还必须要修改其他集合中的相同值的value的属性。举个例子,比如要在三个集合中添加人,第一个是男的,第二个男的,第三个是女的,第四个是男的,分别输出三个集合的人数,然后把第一个人删除,再输出三个集合的人数,程序如下:
LinkedList<Individual> listAll = new LinkedList<Individual>(); LinkedList<Individual> listMale = new LinkedList<Individual>(); LinkedList<Individual> listFemale = new LinkedList<Individual>(); Individual indi1 = new Individual();//Individual是个人类 indi1.Gender = GenderType.M;//男 Individual indi2 = new Individual(); indi2.Gender = GenderType.M; Individual indi3 = new Individual(); indi3.Gender = GenderType.F;//女 Individual indi4 = new Individual(); indi4.Gender = GenderType.M; //根据性别向集合中添加 listAll.AddLast(indi1); listMale.AddLast(indi1); listAll.AddLast(indi2); listMale.AddLast(indi2); listAll.AddLast(indi3); listFemale.AddLast(indi3); listAll.AddLast(indi4); listMale.AddLast(indi4); //分别输出总人数,男性数,女性数,结果为4,3,1 Console.WriteLine("{0}, {1}, {2}", listAll.Count, listMale.Count, listFemale.Count); Console.ReadLine(); //删除集合中的一个男人indi1,这需要即删除listMale和listAll中的两个相同对象 LinkedListNode<Individual> n = listMale.Find(indi1);//首先查到到在listMale中的引用indi1的node(不是对值的查找,而是对引用的查找) listAll.Remove(indi3);//Remove(value) listMale.Remove(n);//Remove(node) //分别输出删除indi1后的总人数,男性数,女性数,结果为3,2,1 Console.WriteLine("{0}, {1}, {2}", listAll.Count, listMale.Count, listFemale.Count); Console.ReadLine();
改进方法,使用三个顺序表来完成,这样对各自顺序表增加要素或者删除要素都不影响其他顺序表,因为顺序表基于数组,对于任何一个value,都有对应的若干引用,value没有链表那种链式结构,它们是靠数组的Index来获得的。更重更要的是,内存中,任何一个value只需要一个拷贝,而不需要多个拷贝,这样就节省了内存,而且对value的修改更加方便,只需要修改一次即可。
我们假设使用的是Add(node)方法添加链表,而非使用Add(value)方法。第一步,往All链表中添加一个男性,同时Male链表中也要加入该男性,第二步,往All链表中添加一个男性,同时Male链表也要加入该男性(重复了),第三步,往All链表加入一个女性,同时Female链表也加入该女性要素,此时,加入的女性成员同时也加入了Male链表中,造成错误。根本原因在于,链表的前后引用关系,三个链表类对其有三个引用,但是操作的确是统一链表。当集合重叠的时候,一定出错。但是要注意的是,这种“同一个结点加入不同链表”的添加方法,只有在自定义的链表泛型类中才能使用,C#的LinkedList<>是禁止向链表中加入一个已经属于其他链表的结点的,下面这段程序因为违法了这一规定而报错:
LinkedList<Individual> listAll = new LinkedList<Individual>(); LinkedList<Individual> listMale = new LinkedList<Individual>(); LinkedList<Individual> listFemale = new LinkedList<Individual>(); Individual indi1 = new Individual();//Individual是个人类 indi1.Gender = GenderType.M;//男 LinkedListNode<Individual> node1 = new LinkedListNode<Individual>(indi1); Individual indi2 = new Individual(); indi2.Gender = GenderType.M; LinkedListNode<Individual> node2 = new LinkedListNode<Individual>(indi2); Individual indi3 = new Individual(); indi3.Gender = GenderType.F;//女 LinkedListNode<Individual> node3 = new LinkedListNode<Individual>(indi3); Individual indi4 = new Individual(); indi4.Gender = GenderType.M; LinkedListNode<Individual> node4 = new LinkedListNode<Individual>(indi4); //根据性别向集合中添加 listAll.AddLast(node1); listMale.AddLast(node1);//error listAll.AddLast(node2); listMale.AddLast(node2); listAll.AddLast(node3); listFemale.AddLast(node3); listAll.AddLast(node4); listMale.AddLast(node4);
若使用自定义自定义链表类(可以加入属于另外一个链表的结点),按上面顺序加入这几个人会有什么后果呢?后果是,第一步,indi1加入了All链表和Male链表;第二步,在All链表尾部加入value是indi2的结点(此时indi2成为链表All和链表Male的尾结点),然后在Male链表尾部(尾部结点的value已经是indi2)再次加入这一结点(因为这个人是男的),这是就会产生这样一个后果:node2的next属性等于他自己,也就是形成了死循环,此时计算All和Male链表的长度,则陷入死循环,无法得出结果。程序如下:
SingleLinkedList<Individual> listAll = new SingleLinkedList<Individual>(); SingleLinkedList<Individual> listMale = new SingleLinkedList<Individual>(); SingleLinkedList<Individual> listFemale = new SingleLinkedList<Individual>(); Individual indi1 = new Individual();//Individual是个人类 indi1.Gender = GenderType.M;//男 Node<Individual> node1 = new Node<Individual>(indi1); Individual indi2 = new Individual(); indi2.Gender = GenderType.M; Node<Individual> node2 = new Node<Individual>(indi2); Individual indi3 = new Individual(); indi3.Gender = GenderType.F;//女 Node<Individual> node3 = new Node<Individual>(indi3); Individual indi4 = new Individual(); indi4.Gender = GenderType.M; Node<Individual> node4 = new Node<Individual>(indi4); //根据性别向集合中添加 listAll.Add(node1); listMale.Add(node1); listAll.Add(node2); listMale.Add(node2);//这一步导致node2.Next = node2;死循环 listAll.Add(node3); listFemale.Add(node3); listAll.Add(node4); listMale.Add(node4); //分别输出总人数,男性数,女性数,无法输出 Console.WriteLine("{0}, {1}, {2}", listAll.GetLength(), listMale.GetLength(), listFemale.GetLength()); Console.ReadLine();
示意图为:
改进方法,使用三个顺序表来完成,这样对各自顺序表增加要素或者删除要素都不影响其他顺序表,因为顺序表基于数组,对于任何一个value,都有对应的若干引用,value没有链表那种链式结构,它们是靠数组的Index来获得的。更重更要的是,内存中,任何一个value只需要一个拷贝,而不需要多个拷贝,这样就节省了内存,而且对value的修改更加方便,只需要修改一次即可。
相关文章推荐
- 从“比较两个含有多个不同元素的集合是否相同”引申出的几种算法
- 从“比较两个含有多个不同元素的集合是否相同”引申出的几种算法
- java找出2个集合相同和不同的元素(以及去除List中的重复元素)
- 使用ArrayList集合,对其添加100个不同的元素: 1.使用add()方法将元素添加到ArrayList集合对象中; 2.调用集合的iterator()方法获得Iterator对象,并调用Ite
- 删除一个单项链表的最中间的元素,要求时间尽可能短(不能使用两次循环)
- 使用HashSet和TreeSet存储多个商品信息,遍历并输出;其中商品属性:编号,名称,单价,出版社;要求向其中添加多个相同的商品,验证集合中元素的唯一性。 提示:向HashSet中添加自定义
- 快速找出List集合的相同与不同元素集合
- 使用ArrayList集合,对其添加10个不同的元素,并使用Iterator遍历该集合
- java找出2个集合相同和不同的元素(以及去除List中的重复元素)
- python求两个列表的的不同元素集合和相同元素的集合
- 假设有两个按元素值递增有序排列的线性表A和B,均以单链表作存储结构,请编写算法将A表和B表归并为一个按元素值递减 有序(即非递增有序,允许表中含有值相同的元素)排列的线性表C,并要求利用原装(即A表和
- java找出2个集合相同和不同的元素(以及去除List中的重复元素)
- 使用ArrayList集合,对其添加100个不同的元素
- 有两等长数组A,B,所含元素相同,但顺序不同,只能取得A数组某值和B数组某值进行比较,比较结果为大于,小于,等于,但是不能取得同一数组A或者B中两个数进行比较,也不能取得某数组中的某个值
- 使用ArrayList集合,对其添加100个不同的元素
- Set集合中元素的保存问题(hashSet和treeSet中不能存放相同元素)
- 使用ArrayList集合,对其添加100个不同的元素:
- 删除一个单项链表的最中间的元素,要求时间尽可能短(不能使用两次循环)java
- 使用ArrayList集合,对其添加100个不同的元素
- 使用ArrayList集合,对其添加100个不同的元素: