服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#集合遍历时删除和增加元素的方法

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

2021-11-29 14:27codingsilence C#

这篇文章主要介绍了C#集合遍历时删除和增加元素的方法,结合实例形式分析了C#针对集合元素的遍历、添加与删除等操作实现方法与注意事项,需要的朋友可以参考下

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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);
      }
    }
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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型的变量标记原顺序表的尾部元素,当删除一个元素时,这个变量需要自减。代码略。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//两个链表的合并
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# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20