欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#集合遍历时删除和增加元素的方法

程序员文章站 2023-10-28 20:47:58
本文实例讲述了c#集合遍历时删除和增加元素的方法。分享给大家供大家参考,具体如下: 大多数时候,遍历集合元素的时候并不需要对元素进行增加或者删除操作,但有些时候则需要,比...

本文实例讲述了c#集合遍历时删除和增加元素的方法。分享给大家供大家参考,具体如下:

大多数时候,遍历集合元素的时候并不需要对元素进行增加或者删除操作,但有些时候则需要,比如,如果集合中盛放的元素是社会上所有的人,那么有人死亡则元素删除,有人出生则是集合元素的增加。对于这种情况,遍历不能按照原来那种方式去做了,而且c#中的集合对于这类有增删动作的遍历,也不支持foreach循环。

有三种办法可以解决这一问题。

第一种方法:使用c#的linkedlist<>双链表。我原来设想,把原来链表需要删除的元素直接remove掉,那些新添加的元素,先装入到一个临时链表中,等循环结束,再用add把临时链表的头结点添加到原来链表的尾部即可,这样算法的复杂度也较低,但是,出乎意料的是,c#的双链表,无法将属于另外一个链表的结点添加到本链表中,其next属性也只读。无奈,只能一边循环,一边在原链表尾端添加结点,这样就需要标记处循环结束的位置,即需要在原来的未改动的链表的尾部结点处结束循环,而不是在改动后的链表的尾部结点处结束。这样就要求在循环开始之前,先获得尾部结点的引用。程序如下(链表中有0-29的整数值结点,遍历时遇到3的整数倍,就在链表尾端添加一个0值结点,遇到2的整数倍就删除结点)

using system;
using system.collections.generic;
using system.componentmodel;
using system.data;
using system.drawing;
using system.linq;
using system.text;
using system.windows.forms;
namespace 集合遍历时删除或增加元素
{
  public partial class form1 : form
  {
    public form1()
    {
      initializecomponent();
    }
    private linkedlist<int> list = new linkedlist<int>();
    //初始化,添加0-29的整数进入链表
    private void button1_click(object sender, eventargs e)
    {
      for (int i = 0; i < 30; i++)
      {
        this.list.addlast(i);
      }
    }
    //遍历链表,做如下操作:
    //遇到能被3整除的,就在该链表后增加一个0元素,遇到能被2整除的就删除该元素
    private void button2_click(object sender, eventargs e)
    {
      linkedlistnode<int> nodenow = this.list.first;//链表第一个元素
      linkedlistnode<int> nodelast = this.list.last;//原链表的最后一个元素,循环结束的标记
      linkedlistnode<int> nodetmp;//临时结点
      //循环结束的条件是,等当前结点是原链表的最后一个结点
      while (nodenow != nodelast)
      {
        //如果能被3整除时,则在链表后加一个0
        if (nodenow.value % 3 == 0)
        {
          this.list.addlast(0);
        }
        //如果能被2整除,则删除该元素
        if (nodenow.value % 2 == 0)
        {
          //如果nodenow被删除了,那么一定不能用next获取下一个要判断的元素
          //因为已经自动向下一个移动了,这是就要在删除nodenow之前,
          //获取它的next,赋给nodetmp,待nodenow删除之后,再把nodetmp的内存赋给nodenow
          nodetmp = nodenow.next;
          this.list.remove(nodenow);
          nodenow = nodetmp;
        }
        else
        {
          //如果不能被2整除,则在链表中保留该元素,并获得下一个并进行判断
          nodenow = nodenow.next;
        }
      }
      //最后不要忘记对nodelast(原链表最后一个元素)本身进行处理,上面的while循环没有包括这个nodelast
      if (nodenow.value % 3 == 0)
      {
        this.list.addlast(0);
      }
      if (nodenow.value % 2 == 0)
      {
        this.list.remove(nodenow);
      }
    }
    //测试结果
    private void button3_click(object sender, eventargs e)
    {
      foreach (int i in this.list)
      {
        console.writeline(i);
      }
    }
  }
}

using system;
using system.collections.generic;
using system.componentmodel;
using system.data;
using system.drawing;
using system.linq;
using system.text;
using system.windows.forms;
namespace 集合遍历时删除或增加元素
{
  public partial class form1 : form
  {
    public form1()
    {
      initializecomponent();
    }
    private linkedlist<int> list = new linkedlist<int>();
    //初始化,添加0-29的整数进入链表
    private void button1_click(object sender, eventargs e)
    {
      for (int i = 0; i < 30; i++)
      {
        this.list.addlast(i);
      }
    }
    //遍历链表,做如下操作:
    //遇到能被3整除的,就在该链表后增加一个0元素,遇到能被2整除的就删除该元素
    private void button2_click(object sender, eventargs e)
    {
      linkedlistnode<int> nodenow = this.list.first;//链表第一个元素
      linkedlistnode<int> nodelast = this.list.last;//原链表的最后一个元素,循环结束的标记
      linkedlistnode<int> nodetmp;//临时结点
      //循环结束的条件是,等当前结点是原链表的最后一个结点
      while (nodenow != nodelast)
      {
        //如果能被3整除时,则在链表后加一个0
        if (nodenow.value % 3 == 0)
        {
          this.list.addlast(0);
        }
        //如果能被2整除,则删除该元素
        if (nodenow.value % 2 == 0)
        {
          //如果nodenow被删除了,那么一定不能用next获取下一个要判断的元素
          //因为已经自动向下一个移动了,这是就要在删除nodenow之前,
          //获取它的next,赋给nodetmp,待nodenow删除之后,再把nodetmp的内存赋给nodenow
          nodetmp = nodenow.next;
          this.list.remove(nodenow);
          nodenow = nodetmp;
        }
        else
        {
          //如果不能被2整除,则在链表中保留该元素,并获得下一个并进行判断
          nodenow = nodenow.next;
        }
      }
      //最后不要忘记对nodelast(原链表最后一个元素)本身进行处理,上面的while循环没有包括这个nodelast
      if (nodenow.value % 3 == 0)
      {
        this.list.addlast(0);
      }
      if (nodenow.value % 2 == 0)
      {
        this.list.remove(nodenow);
      }
    }
    //测试结果
    private void button3_click(object sender, eventargs e)
    {
      foreach (int i in this.list)
      {
        console.writeline(i);
      }
    }
  }
}

第二种方法:使用c#的list<>,list<>是基于数组的顺序表,增加、删除动作时间复杂度较高,不如链表的效率高。其基本原来同第一种方法相似,也需要使用一个int型的变量标记原顺序表的尾部元素,当删除一个元素时,这个变量需要自减。代码略。

第三种方法,自定义单链表泛型类(链表类见)。跟第一种方法比的好处,就是能够灵活实现两个链表的合并,只需要把第二个链表的头结点设置成第一个链表的尾结点的next的结点(或直接add)就可以了。其实对于c#的双链表,我并不是很清楚,为什么addlast()方法,无法将一个链表的元素添加到另一个链表中,而只能添加一个不属于任何链表的结点(有人说第一种方法,其实可以使用结点clone,但是这样无非还是增加算法的空间和时间复杂度,违背了使用链表的本意)。c#之所以不支持这种做法的原因可能是,ms担心你加入的结点,位于一个环状链表上,这样会导致原链表的last属性、count属性等无法计算(形成死循环)。测试代码如下:

//两个链表的合并
linkedlist<int> list = new linkedlist<int>();
for (int i = 0; i < 10; i++)
{
   list.add(i);
}
linkedlist<int> list2 = new linkedlist<int>();
for (int i = 10; i < 20; i++)
{
   list2.add(i);
}
list.add(list2.head);
node<int> n = list.head;
while(n!=null)
{
   console.writeline(n.data);
   n = n.next;
}
console.readline();
console.writeline(list.getlength());
console.readline();
//两个链表的合并
linkedlist<int> list = new linkedlist<int>();
for (int i = 0; i < 10; i++)
{
 list.add(i);
}
linkedlist<int> list2 = new linkedlist<int>();
for (int i = 10; i < 20; i++)
{
 list2.add(i);
}
list.add(list2.head);
node<int> n = list.head;
while(n!=null)
{
 console.writeline(n.data);
 n = n.next;
}
console.readline();
console.writeline(list.getlength());
console.readline();

更多关于c#相关内容感兴趣的读者可查看本站专题:《c#遍历算法与技巧总结》、《c#程序设计之线程使用技巧总结》、《c#操作excel技巧总结》、《c#中xml文件操作技巧汇总》、《c#常见控件用法教程》、《winform控件用法总结》、《c#数据结构与算法教程》、《c#数组操作技巧总结》及《c#面向对象程序设计入门教程

希望本文所述对大家c#程序设计有所帮助。