首页
学习
活动
专区
圈层
工具
发布
39 篇文章
1
【愚公系列】2023年10月 数据结构(零)-数据结构简介
2
【愚公系列】2023年10月 数据结构(一)-数组
3
【愚公系列】2023年11月 数据结构(二)-链表
4
【愚公系列】2023年11月 数据结构(三)-列表
5
【愚公系列】2023年11月 数据结构(四)-栈
6
【愚公系列】2023年11月 数据结构(五)-队列
7
【愚公系列】2023年11月 数据结构(六)-双向队列
8
【愚公系列】2023年11月 数据结构(七)-哈希表
9
【愚公系列】2023年11月 数据结构(八)-二叉树
10
【愚公系列】2023年11月 数据结构(九)-AVL树
11
【愚公系列】2023年11月 数据结构(十)-Trie树
12
【愚公系列】2023年11月 数据结构(十一)-线段树
13
【愚公系列】2023年11月 数据结构(十二)-红黑树
14
【愚公系列】2023年11月 数据结构(十三)-堆
15
【愚公系列】2023年11月 数据结构(十四)-图
16
【愚公系列】2023年11月 七大查找算法(一)-顺序查找
17
【愚公系列】2023年11月 七大查找算法(二)-二分查找
18
【愚公系列】2023年11月 七大查找算法(三)-插值查找
19
【愚公系列】2023年11月 七大查找算法(四)-斐波那契查找
20
【愚公系列】2023年11月 七大查找算法(五)-树查找
21
【愚公系列】2023年11月 七大查找算法(六)-哈希查找
22
【愚公系列】2023年11月 七大查找算法(七)-分块查找
23
【愚公系列】2023年11月 十一大排序算法(零)-排序算法简介
24
【愚公系列】2023年11月 十一大排序算法(一)-冒泡排序
25
【愚公系列】2023年11月 十一大排序算法(二)-快速排序
26
【愚公系列】2023年11月 十一大排序算法(三)-插入排序
27
【愚公系列】2023年11月 十一大排序算法(四)-希尔排序
28
【愚公系列】2023年11月 十一大排序算法(五)-选择排序
29
【愚公系列】2023年11月 十一大排序算法(六)-堆排序
30
【愚公系列】2023年11月 十一大排序算法(七)-归并排序
31
【愚公系列】2023年11月 十一大排序算法(八)-计数排序
32
【愚公系列】2023年11月 十一大排序算法(九)-桶排序
33
【愚公系列】2023年11月 十一大排序算法(十)-基数排序
34
【愚公系列】2023年12月 十一大排序算法(十一)-二叉树排序
35
【愚公系列】2023年12月 五大常用算法(一)-分治算法
36
【愚公系列】2023年12月 五大常用算法(二)-回溯算法
37
【愚公系列】2023年12月 五大常用算法(三)-动态规划算法
38
【愚公系列】2023年12月 五大常用算法(四)-贪心算法
39
【愚公系列】2023年12月 五大常用算法(五)-分支限界算法

【愚公系列】2023年10月 数据结构(一)-数组

🏆 作者简介,愚公搬代码 🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,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.基本思想

数组是一种线性数据结构,其基本思想是将相同类型的元素存储在一块连续的内存空间中,通过数组下标来访问元素。数组的下标从0开始,每个元素在内存中的地址也可以通过下标和数组的起始地址计算得出。

数组的优点是可以快速地访问元素,因为可以通过下标直接定位到元素的内存地址。另外,数组的内存空间是连续的,因此在读取或写入一段连续的元素时,在缓存机制的帮助下会有更好的性能表现。

数组的缺点是其大小是静态的,无法动态扩展或缩小。如果数组已经占用了所有可用的内存空间,但需要添加更多的元素,就需要重新申请一个更大的数组,并将原数组的元素复制到新数组中,这样做效率较低。此外,删除数组中的元素也会涉及到元素的移动,同样会影响效率。

在这里插入图片描述

🔎2.数组常用操作

🦋2.1 初始化数组

在 C# 中,可以使用以下几种方式来初始化数组:

  1. 声明数组的同时进行初始化:
代码语言:c#
复制
int[] numbers = { 1, 2, 3, 4, 5 };
  1. 使用 new 关键字创建数组并进行初始化:
代码语言:c#
复制
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
  1. 先创建数组对象,再进行初始化:
代码语言:c#
复制
int[] numbers = new int[5];
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;
  1. 多维数组的初始化方式:
代码语言:c#
复制
int[,] matrix = new int[,] { { 1, 2 }, { 3, 4 } };
  1. 交错数组的初始化方式:
代码语言:c#
复制
int[][] jaggedArray = new int[2][];
jaggedArray[0] = new int[] { 1, 2, 3 };
jaggedArray[1] = new int[] { 4, 5 };

🦋2.2 访问元素

在C#中,可以使用以下语法初始化一个数组:

代码语言:c#
复制
int[] myArray = new int[] {1, 2, 3, 4, 5};

要访问数组元素,可以使用以下语法:

代码语言:c#
复制
int value = myArray[0];
Console.WriteLine(value); // 输出1

其中,[0]表示访问第一个元素,数组下标从0开始。

在这里插入图片描述
代码语言:c#
复制
/* 随机访问元素 */
int randomAccess(int[] nums) {
	Random random = new();
	// 在区间 [0, nums.Length) 中随机抽取一个数字
	int randomIndex = random.Next(nums.Length);
	// 获取并返回随机元素
	int randomNum = nums[randomIndex];
	return randomNum;
}

在数组中访问元素是非常高效的,我们可以在 O(1) 时间内随机访问数组中的任意一个元素。

🦋2.3 插入元素

可以使用数组(Array)的Copy方法来实现。

代码语言:c#
复制
int[] arr = new int[5] { 1, 2, 3, 4, 5 };
int index = 2; //需要插入元素的位置
int insertValue = 10; //需要插入的元素
int[] newArr = new int[arr.Length + 1]; //新数组比原数组多一个元素

//复制原数组前半部分
Array.Copy(arr, 0, newArr, 0, index);

//插入新元素
newArr[index] = insertValue;

//复制原数组后半部分
Array.Copy(arr, index, newArr, index + 1, arr.Length - index);

//输出新数组
foreach (int num in newArr)
{
    Console.Write(num + " ");
}

运行以上代码,输出结果为:1 2 10 3 4 5。可以看到,原数组中的第3个元素(即值为3的元素)被移动到新数组中的第4个位置,而新元素10被插入到原位置上。

在这里插入图片描述
代码语言:c#
复制
/* 在数组的索引 index 处插入元素 num */
void insert(int[] nums, int num, int index) {
	// 把索引 index 以及之后的所有元素向后移动一位
	for (int i = nums.Length - 1; i > index; i--) {
		nums[i] = nums[i - 1];
	}
	// 将 num 赋给 index 处元素
	nums[index] = num;
}

值得注意的是,由于数组的长度是固定的,因此插入一个元素必定会导致数组尾部元素的“丢失”。

🦋2.4 删除元素

使用Array.Copy()方法创建一个新的数组,将要删除的元素之前的元素复制到新数组中,将要删除的元素之后的元素也复制到新数组中,从而删除该元素。

代码语言:c#
复制
int[] arr = new int[] { 1, 2, 3, 4, 5 };
int removeIndex = 2;

int[] newArr = new int[arr.Length - 1];
Array.Copy(arr, 0, newArr, 0, removeIndex);
Array.Copy(arr, removeIndex + 1, newArr, removeIndex, arr.Length - removeIndex - 1);

foreach (int num in newArr)
{
    Console.WriteLine(num);
}
在这里插入图片描述
代码语言:c#
复制
/* 删除索引 index 处元素 */
void remove(int[] nums, int index) {
	// 把索引 index 之后的所有元素向前移动一位
	for (int i = index; i < nums.Length - 1; i++) {
		nums[i] = nums[i + 1];
	}
}

删除元素完成后,原先末尾的元素变得“无意义”了,所以我们无须特意去修改它。

🦋2.5 遍历数组

在C#中,有许多方法可以遍历数组,以下是几个常见的方法:

  1. 使用for循环遍历数组:
代码语言:c#
复制
int[] arr = { 1, 2, 3, 4, 5 };

for (int i = 0; i < arr.Length; i++)
{
    Console.WriteLine(arr[i]);
}
  1. 使用foreach循环遍历数组:
代码语言:c#
复制
int[] arr = { 1, 2, 3, 4, 5 };

foreach (int item in arr)
{
    Console.WriteLine(item);
}
  1. 使用Array类的静态方法遍历数组:
代码语言:c#
复制
int[] arr = { 1, 2, 3, 4, 5 };

Array.ForEach(arr, item => Console.WriteLine(item));
  1. 使用LINQ查询遍历数组:
代码语言:c#
复制
int[] arr = { 1, 2, 3, 4, 5 };

var result = from item in arr
             select item;

foreach (var item in result)
{
    Console.WriteLine(item);
}

🦋2.6 查找元素

C#中可以使用以下两种方式查找数组元素:

  1. 使用for循环遍历数组,逐个比较元素值:
代码语言:c#
复制
int[] arr = { 1, 2, 3, 4, 5 };
int element = 3;
int index = -1;
for (int i = 0; i < arr.Length; i++)
{
    if (arr[i] == element)
    {
        index = i;
        break;
    }
}
if (index == -1)
{
    Console.WriteLine("元素未找到");
}
else
{
    Console.WriteLine($"元素 {element} 的位置为 {index}");
}
  1. 使用Array类提供的静态方法查找元素:
代码语言:c#
复制
int[] arr = { 1, 2, 3, 4, 5 };
int element = 3;
int index = Array.IndexOf(arr, element);
if (index == -1)
{
    Console.WriteLine("元素未找到");
}
else
{
    Console.WriteLine($"元素 {element} 的位置为 {index}");
}

其中,Array.IndexOf方法接收两个参数,第一个参数为要查找的数组,第二个参数为要查找的元素。如果查找到了元素,返回其在数组中的位置(从0开始),否则返回-1。

🦋2.7 扩容数组

在 C# 中,数组的扩容可以使用 Array 类的 Resize 方法或创建一个新数组并将原始数组中的元素复制到它的方式来实现。

  1. Array.Resize 方法

Array.Resize 方法允许您更改数组的大小。它接受两个参数:要调整大小的数组和新的数组大小。

例如,如果要将一个名为 myArray 的整数数组扩展为 10 个元素,可以使用以下代码:

代码语言:c#
复制
int[] myArray = new int[5];
Array.Resize(ref myArray, 10);

在上面的示例中,使用了 ref 关键字来将 myArray 作为传递给 Resize 方法的参数。

  1. 创建一个新数组并将原始数组中的元素复制到它

如果您想要创建一个新的具有更大大小的数组,则可以使用以下代码:

代码语言:c#
复制
int[] oldArray = new int[5];
int[] newArray = new int[10];

for (int i = 0; i < oldArray.Length; i++)
{
    newArray[i] = oldArray[i];
}

oldArray = newArray;

在上面的示例中,我们先创建了一个名为 oldArray 的数组,它有五个元素。然后,我们创建了一个名为 newArray 的新数组,它有十个元素。接下来,我们使用 for 循环将 oldArray 中的元素复制到 newArray 中,然后使用 oldArray = newArray 将新数组分配给旧数组。现在,oldArray 变成了一个具有十个元素的数组。

需要注意的是,在调整数组大小时,对于值类型元素,新的元素将设置为默认值(例如,在一个 int 数组中,新元素将设置为 0)。对于引用类型元素,新元素将设置为 null。

🔎3.优点和缺点

C#数组的优点包括:

  1. 高效性:数组是一种高效的数据结构,可以快速地读取和写入数组中的元素。
  2. 随机访问能力:可以随机访问数组中的元素,而不必遍历整个数组。
  3. 具有固定长度:数组的长度是固定的,这使得内存分配更加高效。
  4. 支持多维数组:C#的数组可以是多维的,这使得处理二维或三维数据更加方便。

C#数组的缺点包括:

  1. 固定长度:虽然固定长度是数组的一个优点,但它也是它的限制。一旦数组被创建,它的长度就不能改变。
  2. 无法处理非连续数据:如果需要存储非连续的数据,比如链表,那么数组就无法胜任。
  3. 操作较为复杂:在数组中进行插入、删除等操作较为复杂,需要在每个操作中重新排列数组元素的位置,比较耗时。
  4. 数组的大小受限于内存:数组的大小受限于计算机内存的大小,如果数组过大,可能会导致内存不足的问题。

🔎4.应用场景

数组是一种常见的数据结构,广泛应用于编程和数据处理中。以下是数组的一些应用场景:

  1. 数据存储:数组是一种线性数据结构,可以用来存储大量的数据。
  2. 精简代码:数组可以用来存储一组值,可以通过索引来访问数组中的元素,从而避免写重复的代码。
  3. 数据排序:数组可以用来存储一组数据,排序算法可以通过数组来对数据进行排序。
  4. 图像处理:图像数据可以被存储为一个二维数组,每个像素值可以通过数组索引来访问和修改。
  5. 数据统计:数组可以用来存储一组数据,统计算法可以通过数组来对数据进行统计,如求和、平均数等。
  6. 数据结构:数组可以被用作其他数据结构的基础,如栈、队列、堆等。
  7. 多维数组:多维数组可以用来存储复杂的数据结构,如矩阵、图等。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

下一篇
举报
领券