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

作者:codingsilence 时间:2021-12-11 18:53:24 

本文实例讲述了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型的变量标记原顺序表的尾部元素,当删除一个元素时,这个变量需要自减。代码略。

第三种方法,自定义单链表泛型类(链表类见https://www.jb51.net/article/87610.htm)。跟第一种方法比的好处,就是能够灵活实现两个链表的合并,只需要把第二个链表的头结点设置成第一个链表的尾结点的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#,集合,遍历
0
投稿

猜你喜欢

  • Maven install 报错"程序包不存在"问题的解决方法

    2021-05-27 06:08:06
  • mybatis中resultMap 标签的使用教程

    2022-01-15 11:19:42
  • Maven之导入thymeleaf依赖飘红问题及解决

    2023-11-12 12:49:05
  • SpringMVC RESTFul实现列表功能

    2023-10-30 21:15:22
  • 浅谈Mybatis通用Mapper使用方法

    2023-02-15 17:46:52
  • SpringBoot整合MybatisPlus的教程详解

    2023-12-06 18:05:20
  • 详解SpringBoot迭代发布JAR瘦身配置

    2021-11-14 19:10:48
  • IDEA中Spring项目的工程构建

    2023-07-20 13:36:48
  • Java分层概念详解

    2021-12-12 06:29:18
  • Java读写txt文件时防止中文乱码问题出现的方法介绍

    2023-06-23 04:40:32
  • Java简单实现定时器

    2023-07-16 18:10:58
  • C#网络编程基础之进程和线程详解

    2023-03-22 07:38:32
  • MyBatis在注解上使用动态SQL方式(@select使用if)

    2023-09-24 06:52:55
  • Seata 环境搭建部署过程

    2021-09-06 08:45:36
  • Spring Boot加密配置文件特殊内容的示例代码详解

    2023-09-18 08:47:24
  • Java多线程实现Runnable方式

    2022-06-29 17:09:46
  • C# 生成随机数的代码

    2021-06-16 06:05:43
  • Java泛型常见面试题(面试必问)

    2021-11-20 20:51:55
  • java中申请不定长度数组ArrayList的方法

    2023-02-24 17:37:37
  • IDEA中设置代码自动提示为Alt+/的具体做法

    2022-07-06 14:58:32
  • asp之家 软件编程 m.aspxhome.com