数据结构与算法(1)

今天来学习数据结构与算法

第一章:绪论

  1. 数据结构三要素:逻辑结构、存储结构、数据的运算;其中逻辑结构包括线性结构(线性表、栈、队列)和非线性结构(树、图、集合)
  2. 数据是信息的载体,是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。
  3. 数据元素是数据的基本单位,可由若干数据项组成,数据项是构成数据元素的不可分割的最小单位,
  4. 数据对象是具有相同性质的数据元素的集合,是数据的一个子集
  5. 数据类型是一个值的集合和定义在此集合上的一组操作的总称
  6. 数据类型包括:原子类型、结构类型、抽象数据类型
  7. 数据结构是相互之间存在一种或多种特定关系的数据元素的集合,它包括逻辑结构、存储结构和数据运算三方面内容
  8. 数据的逻辑结构和存储结构是密不可分的,算法的设计取决于所选定的逻辑结构,而算法的实现依赖于采用的存储结构
  9. 数据的存储结构主要有顺序存储、连式存储、索引存储和散列存储
  10. 施加在数据上的运算包括运算的定义和实现。运算的定义是针对逻辑结构的,指出运算的功能;运算的实现是针对存储结构的,指出运算的具体操作步骤
  11. 在存储数据时,通常不仅要存储各数据元素的值,而且要存储数据元素之间的关系 对于两种不同的数据结构,逻辑结构或物理结构一定不同吗?
  12. 数据运算也是数据结构的一个重要方面。对于两种不同的数据结构,他们的逻辑结构和物理结构完全有可能相同(比如二叉树和二叉排序树)
  13. 链式存储设计时,各个不同结点的存储空间可以不连续,但结点内的存储单元地址必须连续
  14. 算法是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每条指令包括一个或多个操作。
  15. 算法的五个特性:有穷性、确定性、可行性、输入、输出(字面意思,第一遍看的话建议看看书具体概念)
  16. 通常设计一个好的算法应考虑:正确性、可读性、健壮性、效率与低存储量需求 算法的时间复杂度不仅依赖于问题的规模n,也取决于待输入数据的性质
  17. 若输入数据所占空间只取决于问题本身而和算法无关,则只需分析除输入和程序之外的额外空间
  18. 算法原地工作是指算法所需辅助空间为常量,即O(1)
  19. 一个算法应该是问题求解步骤的描述
  20. 所谓时间复杂度,是指最欢情况下估算算法执行时间的一个上界
  21. 同一个算法,实现语言的级别越高,执行效率越低 ————————————————

第二章 线性表

图片 定义:零个或多个数据元素的有限序列

一、线性表的顺序存储结构

好的,下面是一个使用Markdown格式编写的线性表的顺序存储结构的描述,包括图形结构和代码示例。

1. 结构描述

线性表的顺序存储结构是一种将线性表中的元素存储在一个连续的内存区域中的数据结构。每个元素占用一个固定大小的空间,通过数组索引来访问元素。

2. 图形结构描述

假设我们有一个线性表 [a, b, c, d, e],其顺序存储结构可以表示如下:

a1 a2 a3 a4 a5
1 2 3 4 5
loc loc(a_i) loc(a_i+1) loc(a_i+2) loc(a_i+3)

其中,每个元素按顺序存储在数组中,可以通过索引直接访问。

4. 解释

  • 构造函数:初始化一个固定大小的数组 data 和一个长度计数器 length
  • 插入方法:在指定位置插入一个新元素,如果位置超出范围或数组已满,则抛出错误。
  • 删除方法:删除指定位置的元素,如果位置超出范围,则抛出错误。
  • 获取方法:返回指定位置的元素,如果位置超出范围,则抛出错误。
  • 查找方法:查找并返回指定值的索引,如果未找到则返回 -1
  • 打印方法:打印当前线性表的内容。

线性表的顺序存储结构

存储位置公式

在线性表的顺序存储结构中,每个元素存储在连续的内存区域中。假设线性表的第一个元素存储在内存地址 Loc(a1) 处,每个元素占用 k 个存储单元,则第 i 个元素的存储位置可以通过以下公式计算:

其中:

  • (\text{Loc}(a_i)) 是第 (i) 个元素的存储位置。
  • (\text{Loc}(a_1)) 是第一个元素的存储位置。
  • (i) 是元素的索引(从1开始)。
  • (k) 是每个元素占用的存储单元数。

示例

假设线性表的第一个元素 a1 存储在内存地址 1000 处,每个元素占用 4 个存储单元,那么第 3 个元素 a3 的存储位置计算如下:

因此,第 3 个元素 a3 的存储位置是 1008

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
77
78
79
80
81
82
83
84
85
86
87
88
#include <stdio.h>
#include <stdlib.h>
//线性表的声明
#define MAXSIZE 100
typedef int ElemType; //定义元素类型为整型
typedef struct {
ElemType data[MAXSIZE]; //存放元素
int length; //长度
} SqList; //类型
//创建顺序表
void CreateList(SqList &L,ElemType a[], int n) //输入顺序表元素,n为元素个数
{
int i=0,k=0; //i为数组下标,k为顺序表长度
L = (SqList*)malloc(sizeof(SqList)); //申请顺序表空间
for(i=0;i<n;i++) { //依次输入元素
L->data[i] = a[i]; //顺序表元素赋值
k++; //顺序表长度加一
}
L->length = k; //顺序表长度赋值
return;
}

//初始化顺序表
void InitList(SqList &L) {
L = (SqList*)malloc(sizeof(SqList));
L->length = 0;
return;
}

//插入元素
bool ListInsert(SqList &L, int i, ElemType e) {
if (i < 1 || i > L.length + 1) return false;
for (int j = L.length; j >= i; j--) {
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;
L.length++;
return true;
}
//删除元素
bool ListDelete(SqList &L, int i, ElemType &e) {
if (i < 1 || i > L.length) return false;
e = L.data[i - 1];
for (int j = i; j < L.length; j++) {
L.data[j - 1] = L.data[j];
}
L.length--;
return true;
}

//查找元素
int LocateElem(SqList L, ElemType e) {
for (int i = 0; i < L.length; i++) {
if (L.data[i] == e) return i + 1;
return 0;

}

}

//遍历顺序表
void ListTraverse(SqList L) {
for (int i = 0; i < L.length; i++) {
printf("%d ", L.data[i]);
}
}
//判断顺序表是否为空
bool Empty(SqList L) {
return L.length == 0;
}
void destroy(SqList &L){
free(L);
}

//验证函数
int main() {
int a[] = {1, 2, 3, 4, 5};
SqList L;
CreateList(L, a, 5);
ListInsert(L, 3, 6);
ListDelete(L, 3, e);
printf("查找元素6的位置为:%d\n", LocateElem(L, 6));
ListTraverse(L);
destroy(L);
return 0;
}


顺序表删除算法详解

概述

顺序表是一种线性数据结构,其中的数据元素在内存中是连续存储的。删除操作是指从顺序表中移除指定位置的元素,并调整后续元素的位置,以保持数据的连续性。

算法步骤

1. 参数检查

  • 检查传入的索引是否有效(即是否在合法范围内)。
  • 如果索引无效,返回错误或抛出异常。

2. 元素移动

  • 从索引位置开始,将后续的所有元素向前移动一位。
  • 这一步的时间复杂度为 O(n),其中 n 是顺序表的长度。

3. 更新长度

  • 减少顺序表的长度,表示已删除一个元素。

4. 返回结果

  • 根据需求返回被删除的元素或其他相关信息。

元素移动次数分析

假设顺序表的长度为 n,删除位置为 i(0 ≤ i < n)。

  • 如果删除位置为 i,则需要移动 n - i - 1 个元素。

平均情况下,删除操作需要移动的元素数量为:

计算上述求和公式:

因此,平均移动次数为:

示例代码

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
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100

typedef int ElemType;
typedef struct {
ElemType data[MAXSIZE];
int length;
} SqList;

/**
* 删除顺序表中指定位置的元素
*
* @param list 顺序表指针
* @param index 要删除的元素的索引
* @return 成功返回被删除的元素,失败返回 -1
*/
ElemType deleteElement(SqList *list, int index) {
if (index < 0 || index >= list->length) {
// 索引无效
return -1;
}

ElemType deletedElement = list->data[index];

// 将后续元素前移
for (int i = index; i < list->length - 1; i++) {
list->data[i] = list->data[i + 1];
}

// 更新长度
list->length--;

return deletedElement;
}

int main() {
SqList list;
list.length = 5;
list.data[0] = 10;
list.data[1] = 20;
list.data[2] = 30;
list.data[3] = 40;
list.data[4] = 50;

int indexToDelete = 2;
ElemType deletedElement = deleteElement(&list, indexToDelete);

if (deletedElement != -1) {
printf("删除的元素是: %d\n", deletedElement);
printf("删除后的顺序表: ");
for (int i = 0; i < list.length; i++) {
printf("%d ", list.data[i]);
}
printf("\n");
} else {
printf("删除失败,索引无效。\n");
}

return 0;
}

时间复杂度

  • 最佳情况:O(1)(删除最后一个元素)
  • 最坏情况:O(n)(删除第一个元素)
  • 平均情况:O(n)

空间复杂度

  • O(1):删除操作只涉及原地修改,不需要额外的空间。

注意事项

  • 在实际应用中,如果频繁进行删除操作,可以考虑使用链表等其他数据结构来优化性能。
  • 删除操作后,确保释放或重置不再使用的内存,避免内存泄漏。

平均移动次数总结

  • 平均移动次数:(\frac{n-1}{2})
  • 这意味着在平均情况下,删除一个元素需要移动大约一半的元素。

线性表的链式存储结构详细解释

概述

图形描述

线性表的链式存储结构通过指针将节点连接起来,每个节点包含数据部分和指针部分。以下是一个简单的单链表的图形描述:

1
2
3
4
5
+--------+     +--------+     +--------+
| data | | data | | data |
| next | --> | next | --> | next | --> NULL
+--------+ +--------+ +--------+
Node 1 Node 2 Node 3

链表与顺序表比较

存储方式

  • 顺序表:数据元素在内存中连续存储。
  • 链表:数据元素通过指针连接,存储位置可以不连续。

插入和删除操作

  • 顺序表:插入和删除操作需要移动大量元素,时间复杂度为 O(n)。
  • 链表:插入和删除操作只需修改指针,时间复杂度为 O(1)。

空间利用率

  • 顺序表:需要预先分配固定大小的存储空间,可能导致空间浪费。
  • 链表:动态分配存储空间,空间利用率更高。

单链表

C语言代码

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
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

// 定义链表节点结构
typedef struct Node {
ElemType data;
struct Node *next;
} Node;

// 创建新节点
Node* createNode(ElemType data) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}

// 插入节点到链表头部
void insertAtHead(Node **head, ElemType data) {
Node *newNode = createNode(data);
newNode->next = *head;
*head = newNode;
}

// 删除链表中的节点
void deleteNode(Node **head, ElemType data) {
Node *current = *head;
Node *previous = NULL;

while (current != NULL && current->data != data) {
previous = current;
current = current->next;
}

if (current == NULL) {
printf("元素 %d 未找到\n", data);
return;
}

if (previous == NULL) {
*head = current->next;
} else {
previous->next = current->next;
}

free(current);
}

// 打印链表
void printList(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}

int main() {
Node *head = NULL;

insertAtHead(&head, 30);
insertAtHead(&head, 20);
insertAtHead(&head, 10);

printf("初始链表: ");
printList(head);

deleteNode(&head, 20);
printf("删除 20 后的链表: ");
printList(head);

return 0;
}

应用实例及图形

初始链表

1
2
3
4
5
+--------+     +--------+     +--------+
| data | | data | | data |
| next | --> | next | --> | next | --> NULL
+--------+ +--------+ +--------+
10 20 30

删除 20 后的链表

1
2
3
4
5
+--------+     +--------+
| data | | data |
| next | --> | next | --> NULL
+--------+ +--------+
10 30

双链表

C语言代码

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
77
78
79
80
81
82
83
84
85
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

// 定义双链表节点结构
typedef struct DNode {
ElemType data;
struct DNode *prev;
struct DNode *next;
} DNode;

// 创建新节点
DNode* createDNode(ElemType data) {
DNode *newNode = (DNode *)malloc(sizeof(DNode));
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}

// 插入节点到双链表头部
void insertAtHeadDList(DNode **head, ElemType data) {
DNode *newNode = createDNode(data);
if (*head == NULL) {
*head = newNode;
} else {
newNode->next = *head;
(*head)->prev = newNode;
*head = newNode;
}
}

// 删除双链表中的节点
void deleteNodeDList(DNode **head, ElemType data) {
DNode *current = *head;

while (current != NULL && current->data != data) {
current = current->next;
}

if (current == NULL) {
printf("元素 %d 未找到\n", data);
return;
}

if (current->prev != NULL) {
current->prev->next = current->next;
} else {
*head = current->next;
}

if (current->next != NULL) {
current->next->prev = current->prev;
}

free(current);
}

// 打印双链表
void printDList(DNode *head) {
DNode *current = head;
while (current != NULL) {
printf("%d <-> ", current->data);
current = current->next;
}
printf("NULL\n");
}

int main() {
DNode *head = NULL;

insertAtHeadDList(&head, 30);
insertAtHeadDList(&head, 20);
insertAtHeadDList(&head, 10);

printf("初始双链表: ");
printDList(head);

deleteNodeDList(&head, 20);
printf("删除 20 后的双链表: ");
printDList(head);

return 0;
}

应用示例及图形

初始双链表

1
2
3
4
5
6
+--------+     +--------+     +--------+
| data | | data | | data |
| prev | | prev | | prev |
| next | <-> | next | <-> | next | <-> NULL
+--------+ +--------+ +--------+
10 20 30

删除 20 后的双链表

1
2
3
4
5
6
+--------+     +--------+
| data | | data |
| prev | | prev |
| next | <-> | next | <-> NULL
+--------+ +--------+
10 30

循环链表

C语言代码

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

// 定义循环链表节点结构
typedef struct CNode {
ElemType data;
struct CNode *next;
} CNode;

// 创建新节点
CNode* createCNode(ElemType data) {
CNode *newNode = (CNode *)malloc(sizeof(CNode));
newNode->data = data;
newNode->next = NULL;
return newNode;
}

// 插入节点到循环链表头部
void insertAtHeadCList(CNode **head, ElemType data) {
CNode *newNode = createCNode(data);
if (*head == NULL) {
*head = newNode;
newNode->next = newNode;
} else {
newNode->next = *head;
CNode *tail = *head;
while (tail->next != *head) {
tail = tail->next;
}
tail->next = newNode;
*head = newNode;
}
}

// 删除循环链表中的节点
void deleteNodeCList(CNode **head, ElemType data) {
if (*head == NULL) {
printf("链表为空\n");
return;
}

CNode *current = *head;
CNode *previous = NULL;

do {
if (current->data == data) {
if (current == *head) {
if (current->next == *head) {
*head = NULL;
} else {
CNode *tail = *head;
while (tail->next != *head) {
tail = tail->next;
}
*head = current->next;
tail->next = *head;
}
} else {
previous->next = current->next;
}
free(current);
return;
}
previous = current;
current = current->next;
} while (current != *head);

printf("元素 %d 未找到\n", data);
}

// 打印循环链表
void printCList(CNode *head) {
if (head == NULL) {
printf("NULL\n");
return;
}

CNode *current = head;
do {
printf("%d -> ", current->data);
current = current->next;
} while (current != head);
printf("HEAD\n");
}

int main() {
CNode *head = NULL;

insertAtHeadCList(&head, 30);
insertAtHeadCList(&head, 20);
insertAtHeadCList(&head, 10);

printf("初始循环链表: ");
printCList(head);

deleteNodeCList(&head, 20);
printf("删除 20 后的循环链表: ");
printCList(head);

return 0;
}

图形

初始循环链表

1
2
3
4
5
6
+--------+     +--------+     +--------+
| data | | data | | data |
| next | --> | next | --> | next | -->
+--------+ +--------+ +--------+
10 20 30
<-- <--

删除 20 后的循环链表

1
2
3
4
5
6
+--------+     +--------+
| data | | data |
| next | --> | next | -->
+--------+ +--------+
10 30
<-- <--

线性表的应用

有序表

C语言代码

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
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

// 定义有序链表节点结构
typedef struct ONode {
ElemType data;
struct ONode *next;
} ONode;

// 创建新节点
ONode* createONode(ElemType data) {
ONode *newNode = (ONode *)malloc(sizeof(ONode));
newNode->data = data;
newNode->next = NULL;
return newNode;
}

// 插入节点到有序链表
void insertToOrderedList(ONode **head, ElemType data) {
ONode *newNode = createONode(data);
ONode *current = *head;
ONode *previous = NULL;

while (current != NULL && current->data < data) {
previous = current;
current = current->next;
}

if (previous == NULL) {
newNode->next = *head;
*head = newNode;
} else {
previous->next = newNode;
newNode->next = current;
}
}

// 打印有序链表
void printOrderedList(ONode *head) {
ONode *current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}

int main() {
ONode *head = NULL;

insertToOrderedList(&head, 30);
insertToOrderedList(&head, 10);
insertToOrderedList(&head, 20);

printf("有序链表: ");
printOrderedList(head);

return 0;
}

有序链表

1
2
3
4
5
+--------+     +--------+     +--------+
| data | | data | | data |
| next | --> | next | --> | next | --> NULL
+--------+ +--------+ +--------+
10 20 30

有序表详解

概述

有序表是一种特殊类型的线性表,其中的数据元素按照某种顺序排列。常见的排序方式有升序和降序。有序表支持高效的查找、插入和删除操作,广泛应用于各种数据处理和检索场景。

基本算法

查找算法

二分查找是一种高效的查找算法,适用于有序表。其基本思想是每次将查找范围缩小一半,直到找到目标元素或确定目标元素不存在。

算法步骤
  1. 初始化:设置两个指针 lowhigh,分别指向有序表的起始位置和结束位置。
  2. 中间位置:计算中间位置 mid
  3. 比较
    • 如果 target 等于 array[mid],返回 mid
    • 如果 target 小于 array[mid],将 high 设置为 mid - 1
    • 如果 target 大于 array[mid],将 low 设置为 mid + 1
  4. 重复:重复步骤 2 和 3,直到 low 超过 high
  5. 未找到:如果 low 超过 high,返回 -1 表示未找到。
C语言代码
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
#include <stdio.h>

int binarySearch(int array[], int target, int low, int high) {
while (low <= high) {
int mid = low + (high - low) / 2;

if (array[mid] == target) {
return mid;
} else if (array[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}

return -1;
}

int main() {
int array[] = {10, 20, 30, 40, 50, 60, 70, 80, 90};
int n = sizeof(array) / sizeof(array[0]);
int target = 40;

int result = binarySearch(array, target, 0, n - 1);

if (result != -1) {
printf("元素 %d 在数组中的索引为 %d\n", target, result);
} else {
printf("元素 %d 未找到\n", target);
}

return 0;
}

插入算法

有序链表插入

在有序链表中插入新元素时,需要找到合适的位置,然后将新元素插入到该位置。

算法步骤
  1. 创建新节点:创建一个包含新数据的新节点。
  2. 遍历链表:从头节点开始遍历链表,找到合适的位置。
  3. 插入新节点:将新节点插入到合适的位置,更新指针。
C语言代码
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
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct Node {
ElemType data;
struct Node *next;
} Node;

Node* createNode(ElemType data) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}

void insertToOrderedList(Node **head, ElemType data) {
Node *newNode = createNode(data);
Node *current = *head;
Node *previous = NULL;

while (current != NULL && current->data < data) {
previous = current;
current = current->next;
}

if (previous == NULL) {
newNode->next = *head;
*head = newNode;
} else {
previous->next = newNode;
newNode->next = current;
}
}

void printList(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}

int main() {
Node *head = NULL;

insertToOrderedList(&head, 30);
insertToOrderedList(&head, 10);
insertToOrderedList(&head, 20);

printf("有序链表: ");
printList(head);

return 0;
}

删除算法

有序链表删除

在有序链表中删除指定元素时,需要找到该元素,然后将其从链表中移除。

算法步骤
  1. 遍历链表:从头节点开始遍历链表,找到要删除的节点。
  2. 删除节点:更新指针,将要删除的节点从链表中移除。
  3. 释放内存:释放被删除节点的内存。
C语言代码
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
void deleteFromOrderedList(Node **head, ElemType data) {
Node *current = *head;
Node *previous = NULL;

while (current != NULL && current->data < data) {
previous = current;
current = current->next;
}

if (current == NULL || current->data != data) {
printf("元素 %d 未找到\n", data);
return;
}

if (previous == NULL) {
*head = current->next;
} else {
previous->next = current->next;
}

free(current);
}

int main() {
Node *head = NULL;

insertToOrderedList(&head, 30);
insertToOrderedList(&head, 10);
insertToOrderedList(&head, 20);

printf("初始有序链表: ");
printList(head);

deleteFromOrderedList(&head, 20);
printf("删除 20 后的有序链表: ");
printList(head);

return 0;
}

归并算法

归并排序(Merge Sort)

归并排序是一种分治算法,通过将数组分成两半,分别对两半进行排序,然后再将两半合并成一个有序数组。

算法步骤
  1. 分解:将数组分成两半,递归地对每半进行排序。
  2. 合并:将两个有序子数组合并成一个有序数组。
C语言代码
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
#include <stdio.h>
#include <stdlib.h>

void merge(int array[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;

int L[n1], R[n2];

for (int i = 0; i < n1; i++) {
L[i] = array[left + i];
}
for (int j = 0; j < n2; j++) {
R[j] = array[mid + 1 + j];
}

int i = 0, j = 0, k = left;

while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
array[k] = L[i];
i++;
} else {
array[k] = R[j];
j++;
}
k++;
}

while (i < n1) {
array[k] = L[i];
i++;
k++;
}

while (j < n2) {
array[k] = R[j];
j++;
k++;
}
}

void mergeSort(int array[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;

mergeSort(array, left, mid);
mergeSort(array, mid + 1, right);

merge(array, left, mid, right);
}
}

void printArray(int array[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", array[i]);
}
printf("\n");
}

int main() {
int array[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(array) / sizeof(array[0]);

printf("初始数组: ");
printArray(array, n);

mergeSort(array, 0, n - 1);

printf("排序后的数组: ");
printArray(array, n);

return 0;
}

有序表的应用

数据检索

有序表在数据检索中非常高效,特别是当数据量较大时。例如,在数据库系统中,索引通常使用有序表来加速查询操作。

优先队列

有序表可以用于实现优先队列,其中插入和删除操作都保持数据的有序性。优先队列在任务调度、事件处理等场景中非常有用。

统计分析

有序表可以用于统计分析,例如计算中位数、百分位数等。有序表的有序性使得这些统计操作更加高效。

排序

有序表本身就是一个有序的数据结构,可以直接用于排序。归并排序就是一种基于有序表的排序算法。

通过这些详细的解释和示例代码,希望你能更好地理解有序表的基本算法和归并算法,以及它们在实际应用中的重要性。