【愚公系列】2023年12月 数据结构(三)-列表

举报
愚公搬代码 发表于 2023/12/30 23:54:34 2023/12/30
【摘要】 数据结构是计算机科学中的一个重要概念,它描述了数据之间的组织方式和关系,以及对这些数据的访问和操作。常见的数据结构有:数组、链表、栈、队列、哈希表、树、堆和图。

🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏

🚀前言

数据结构是计算机科学中的一个重要概念,它描述了数据之间的组织方式和关系,以及对这些数据的访问和操作。常见的数据结构有:数组、链表、栈、队列、哈希表、树、堆和图。

  1. 数组(Array):是一种线性数据结构,它将一组具有相同类型的数据元素存储在一起,并为每个元素分配一个唯一的索引。数组的特点是具有随机访问的能力。

  2. 链表(Linked List):也是一种线性数据结构,它由一系列的节点组成,每个节点包含数据和指向下一个节点的引用。链表的特点是可以动态地插入或删除节点,但访问某个节点时需要从头开始遍历。

  3. 栈(Stack):是一种后进先出(LIFO)的数据结构,它只能在栈顶进行插入和删除操作。栈通常用于实现递归算法、表达式求值和内存管理等场景。

  4. 队列(Queue):是一种先进先出(FIFO)的数据结构,它可以在队尾插入元素,在队头删除元素。队列通常用于数据的缓存、消息队列和网络通信等场景。

  5. 哈希表(Hash Table):也称为散列表,它是一种根据关键字直接访问数据的数据结构。哈希表通常由数组和散列函数组成,可以在常数时间内进行插入、删除和查找操作。

  6. 树(Tree):是一种非线性数据结构,它由一系列的节点组成,每个节点可以有若干个子节点。树的特点是可以动态地插入或删除节点,常见的树结构包括二叉树、平衡树和搜索树等。

  7. 堆(Heap):是一种特殊的树结构,它通常用于实现优先队列和堆排序等算法。堆分为最大堆和最小堆,最大堆的每个节点的值都大于等于其子节点的值,最小堆则相反。

  8. 图(Graph):是一种由节点和边组成的非线性数据结构,它可以用来表示各种实体之间的关系,如社交网络、路线图和电路图等。图的遍历和最短路径算法是常见的图算法。

🚀一、列表

🔎1.基本思想

列表是一种线性数据结构,它由一系列元素组成,每个元素可以有一个前驱和一个后继。列表的基本思想是将元素按照一定顺序组织起来,并且支持在列表中插入、删除和遍历元素。

列表可以使用数组或链表实现。在数组实现中,列表的元素在内存中是连续的,而在链表实现中,元素可以在内存中任意位置。列表的一个重要特点是支持快速随机访问,因为元素在数组实现中是连续存储的。

列表的操作包括插入、删除、遍历等。在数组实现中,插入和删除操作需要将后续元素进行移动,所以时间复杂度为O(n)。而在链表实现中,插入和删除操作只需要修改节点的指针,时间复杂度为O(1)。遍历列表需要将每个元素依次访问,时间复杂度为O(n)。

列表具有广泛的应用,例如存储数组、字符串等数据、实现队列、栈、哈希等数据结构,以及其它需要按序访问元素的场合。

🔎2.列表常用操作

🦋2.1 初始化列表

1、自定义列表的初始化

C#中的列表可以使用以下语法进行初始化:

  1. 使用花括号{}进行初始化,每个元素用逗号分隔:
List<int> myList = new List<int>() { 1, 2, 3, 4, 5 };
  1. 使用Add方法添加元素:
List<int> myList = new List<int>();
myList.Add(1);
myList.Add(2);
myList.Add(3);
  1. 使用数组初始化列表:
int[] myArray = {1,2,3,4,5};
List<int> myList = new List<int>(myArray);

注意,以上初始化方法都需要在列表变量声明时进行。如果需要在后续添加元素,可以使用Add方法进行添加。

2、内置列表的初始化

当然C#中链表的初始化可以使用LinkedList类。以下是示例代码:

LinkedList<int> list = new LinkedList<int>();

这将创建一个空链表,你可以通过使用AddLast()方法将元素添加到末尾,使用AddFirst()方法将元素添加到开头。你可以使用foreach循环遍历链表中的元素。例如:

list.AddLast(1);
list.AddLast(2);
list.AddFirst(3);

foreach (int item in list)
{
    Console.WriteLine(item);
}

这将输出:

3
1
2

🦋2.2 访问元素

在C#中,可以通过以下方式来访问列表中的元素:

  1. 通过索引访问元素:

可以使用方括号和元素的索引值来访问特定位置的元素。例如,myList[0]将访问列表中的第一个元素。

  1. 遍历列表中的元素:

可以使用循环遍历整个列表中的元素。例如,使用foreach循环可以遍历列表中的所有元素:

foreach (var item in myList)
{
    Console.WriteLine(item);
}
  1. 列表的LINQ操作:

C#中的LINQ操作可用于查询和操作列表。可以使用WhereSelectOrderBy等函数进行筛选、投影和排序等操作。例如,以下代码将从列表中选择所有大于10的元素:

var newList = myList.Where(x => x > 10).ToList();

🦋2.3 插入与删除元素

C#中的列表类(List)提供了许多方法来插入和删除元素。以下是一些常用的方法:

  1. Add():向列表的末尾添加一个元素。
List<int> myList = new List<int>();
myList.Add(1);
  1. Insert():在指定索引处插入一个元素。
List<int> myList = new List<int>();
myList.Insert(0, 1);
  1. Remove():删除列表中的指定元素。
List<int> myList = new List<int>{1, 2, 3};
myList.Remove(2); // myList变成了{1, 3}
  1. RemoveAt():删除列表中指定索引处的元素。
List<int> myList = new List<int>{1, 2, 3};
myList.RemoveAt(1); // myList变成了{1, 3}
  1. Clear():清空列表中的所有元素。
List<int> myList = new List<int>{1, 2, 3};
myList.Clear(); // myList变成了{}

🦋2.4 遍历列表

在C#中,有多种方法可以遍历列表元素:

  1. 使用 for 循环:

您可以使用 for 循环来迭代列表中的元素。这是最基本的方法,因为您可以通过索引号访问列表元素。例如:

List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
for (int i = 0; i < list.Count; i++)
{
    Console.WriteLine(list[i]);
}
  1. 使用 foreach 循环:

使用 foreach 循环可以更加简洁的实现对列表元素的迭代。例如:

List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
foreach (var item in list)
{
    Console.WriteLine(item);
}
  1. 使用 LINQ:

使用LINQ的查询语句,可以方便地过滤、排序、映射和聚合列表数据。例如:

List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
var filteredList = from i in list
                   where i > 3
                   select i;
foreach (var item in filteredList)
{
    Console.WriteLine(item);
}
  1. 使用 Lambda 表达式:

您可以使用 Lambda 表达式来创建委托,以便在遍历列表时执行特定操作。例如:

List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
list.ForEach(item =>
    Console.WriteLine(item));

🦋2.5 拼接列表

在C#中进行列表拼接的方法有以下几种:

1.使用List.AddRange方法

List.AddRange方法可以将一个列表中的元素全部添加到另外一个列表中。示例如下:

List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int> { 4, 5, 6 };
list1.AddRange(list2);

2.使用LINQ的Concat方法

使用LINQ的Concat方法可以将两个列表连接起来。示例如下:

List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int> { 4, 5, 6 };
List<int> result = list1.Concat(list2).ToList();

3.使用List.InsertRange方法

使用List.InsertRange方法可以在指定位置插入一个列表中的元素。示例如下:

List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = new List<int> { 4, 5, 6 };
list1.InsertRange(1, list2);

以上方法都可以实现列表的拼接操作,具体使用哪种方法可以根据实际情况选择。

🦋2.6 排序列表

可以使用List<T>类的Sort()方法来对列表进行排序。该方法接受一个参数,即一个委托,用于比较两个元素的大小关系。

例如,对一个包含整数的List进行升序排序:

List<int> myList = new List<int>{ 4, 2, 8, 1, 5 };
myList.Sort((a, b) => a.CompareTo(b));

也可以使用lambda表达式实现同样的功能:

myList.Sort((a, b) => a - b);

如果要进行降序排序,只需将比较委托中的参数顺序交换即可:

myList.Sort((a, b) => b.CompareTo(a)); //或者 myList.Sort((a, b) => b - a);

🔎3.列表实现

在C#中,可以通过自定义一个类来实现列表的功能,以下是一个简单的实现示例:

public class MyList<T>
{
    private T[] elements;
    private int count;

    public MyList(int capacity)
    {
        elements = new T[capacity];
        count = 0;
    }

    public int Count
    {
        get { return count; }
    }

    public void Add(T element)
    {
        if (count == elements.Length)
        {
            Array.Resize(ref elements, elements.Length * 2);
        }
        elements[count++] = element;
    }

    public T Get(int index)
    {
        if (index < 0 || index >= count)
        {
            throw new IndexOutOfRangeException();
        }
        return elements[index];
    }

    public void Set(int index, T element)
    {
        if (index < 0 || index >= count)
        {
            throw new IndexOutOfRangeException();
        }
        elements[index] = element;
    }

    public void RemoveAt(int index)
    {
        if (index < 0 || index >= count)
        {
            throw new IndexOutOfRangeException();
        }
        for (int i = index; i < count - 1; i++)
        {
            elements[i] = elements[i + 1];
        }
        count--;
    }
}

以上定义了一个类型参数为T的泛型类MyList<T>,其中包含了增加元素、获取元素、设置元素、删除元素等常见的列表操作方法。使用示例:

MyList<string> myList = new MyList<string>(10);
myList.Add("hello");
myList.Add("world");
myList.Add("!");
Console.WriteLine(myList.Get(1)); //输出:world
myList.Set(0, "hi");
myList.RemoveAt(2);
Console.WriteLine(myList.Count); //输出:2

🔎4.优点和缺点

列表(List)是一种基本的数据结构,可以存储一组元素,并按照一定的顺序排列。列表的优点和缺点如下:

优点:

  1. 灵活性:列表可以动态添加和删除元素,适用于需要频繁修改元素的场景。
  2. 可附加的元信息:列表中的元素可以携带附加信息,如元素的唯一标识符、元素的创建时间等,便于后续对元素的处理。
  3. 支持索引:列表支持按照下标访问元素,方便对元素进行读取和修改操作。
  4. 空间效率高:列表在存储元素时只需要按顺序排列,不需要为每个元素预留空间。

缺点:

  1. 访问效率低:在大型列表中查找和访问元素时效率较低,需要遍历整个列表。
  2. 插入和删除效率低:由于需要维护元素的顺序,插入和删除操作比较耗时。
  3. 空间浪费:由于列表内部存储的元素是连续的,当需要插入或删除元素时,可能需要移动大量元素,导致空间浪费。
  4. 不适合高并发场景:由于列表对于并发访问的支持较弱,不适合高并发的场景。

🔎5.应用场景

列表在数据结构中被广泛应用,并且是一种基本的数据结构类型之一。以下是列表的一些应用场景:

  1. 数据存储:列表可以用于存储一系列数据元素,例如存储学生的成绩、存储商品的信息、存储音乐播放列表等。

  2. 数据处理:列表可以用于对一组数据进行处理,例如排序、筛选、搜索等。

  3. 栈和队列的实现:栈和队列都可以通过列表来实现。

  4. 迭代器:列表可以被用作迭代器,使得可以对数据进行迭代处理。

  5. 图的遍历:图的遍历算法中,可以使用列表来存储已访问和未访问的节点。

  6. 数据结构的实现:列表也可以用于实现其他数据结构,例如链表和哈希表等。

列表是一种非常常用的数据结构类型,它可以用于各种不同的应用场景,帮助我们更方便地管理和处理数据。


🚀二、列表扩展

🔎1.Array

数组在C#中最早出现的。在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单。

<span style="font-family:SimSun;font-size:18px;">//数组  
string[] s=new string[2];  
  
//赋值  
s[0]="a";  
s[1]="b";  
//修改  
s[1]="a1";  
</span>

优点:数组在内存中是连续存储的、所以它的索引速度是非常快的、时间复杂度为O(1)、而且它的赋值/修改/获取元素也是非常简单的。

缺点:

1、定义数组的时候需要指定数组的长度(过长会造成内存浪费、过短会导致程序异常System.IndexOutOfRangeException:“索引超出数组界限”)

2、插入和删除元素效率低、也比较麻烦。

在不清楚数组长度的时候、就很尴尬了。 所以C#提供了ArrayList了来处理这些问题…

🔎2.ArrayList

使用大小会根据需要动态增加的数组。

//初始化
ArrayList list = new ArrayList();

//添加元素
list.Add(1);
list.Add("A");
list.Add(0.1);

//修改元素
list[2] = "B";

//指定索引插入元素
list.Insert(1, "ABC");
            
//移除元素
list.RemoveAt(1);

优点:

1、ArrayList大小会根据需要动态增加的数组。

2、实现了IList接口、可以方便的对数据进行添加、插入和删除。

缺点:

1、ArrayList会把插入的数据都当做object类型来存储、在操作数据的时候可能会因为类型不匹配而出现异常、它是非类型安全的对象。

2、由于存储的是object类型、在使用的时候进行类型转换、会造成装箱拆箱、从而损耗性能。

装箱:把值类型转换成引用类型;

拆箱:把引用类型转换成值类型。

//装箱
int i = 1;
object obj = (object)i;
//拆箱
int j = (int)obj;

由于ArrayList存在类型不安全、装箱拆箱损耗性能。.NET Framework 2.0 推出了List<T>

🔎3.List<T>

表示可通过索引访问的对象的强类型列表。 提供用于对列表进行搜索、排序和操作的方法。

//初始化
List<int> list = new List<int>();

//添加
list.Add(12);
list.Add(34);

//编译器会进行类型验证、下面代码编译失败
//list.Add("ABC");

//修改
list[0] = 1;

//移除
list.RemoveAt(0);

优点:由于泛型List是强类型、编译器会验证类型安全。这样就避免了类型的不安全、以及数据强制转换导致装箱拆箱损耗性能。

备注:哈希表(散列),就是数组的升级版通过hash运算快速查找到值,数组下标就是哈希值。(前512是int,后才是哈希)

🚀感谢:给读者的一封信

亲爱的读者,

我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。

如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。

我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。

如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。

在这里插入图片描述

再次感谢您的阅读和支持!

最诚挚的问候, “愚公搬代码”

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。