我们存储很多数的时候,通常使用数组,但是数组不够灵活。

哦?为什么说不灵活?

我们如果要在一个数组前面或者中间插入一个数,就会很麻烦。

假设我们有一个数组a,里面是排序好的数字,我们要将7按大小顺序插入数组

我们就得把后面的数全都依次往后移一位,再将7放入。

这样如果后面的数非常多的话就会很耽误时间。

所以我们需要用到链表

链表就是利用结构体指针,在存储数据的同时,存储一个指向下一个结点的指针。

这样我们要插入数字的时候,只要修改下指针的指向,就可以快速的进行插入或取出之类的操作。

链表有很多种:

单链表:每个结点记录后继(图片演示的就是)

双链表:每个结点记录前驱和后继,它比单链多了个往前走的功能

循环单链表:将单链表的最后一个结点的后继指向第一个结点,形成一个环形结构

循环双链表:将双链表连成环形

…(还有几种就不一一列述了)

这里我们设计一个程序实现一下链表,首先输入四个按大小顺序排列的数字,然后再输入要插入的数字,

程序会输出插入后的排列

先上代码

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
#include <iostream>
using namespace std;

struct node {
int data;//存数据
node* next;//后继指针
};

int main()
{
int a;
node* head, * p, * q = NULL;
head = NULL;
for (int i = 1; i < 5; i++) {
//用指针p指向一个动态申请的node大小的空间
p = (node*)malloc(sizeof(node));
cin >> a;
//将数据存入当前结点(p指向的结点)
p->data = a;
p->next = NULL;

if (head == NULL)head = p;//如果是第一个结点,就将头指针指向当前结点
else q->next = p;//否则将上一个结点的后继指针指向当前结点
q = p;//将q指向当前结点
}

//插入数据
int b;
cin >> b;
node* t = head;//从链表头开始遍历
while (t != NULL) {
if (t->next->data > b) {
p = (node*)malloc(sizeof(node));
//将数据存入当前结点(p指向的结点)
p->data = b;
p->next = t->next;//将当前结点的后继指针指向下一结点
t->next = p;//将上一结点的后继指针指向当前结点
break;
}
t = t->next;//下一结点
}

//输出
t = head;//从链表头开始遍历
while (t != NULL) {
cout << t->data << endl;
t = t->next;//下一结点
}

//释放动态申请的空间(确保安全)
t = head;
while (t != NULL) {
node* current = t;//记录当前结点
t = t->next;//下一结点
free(current);
}
return 0;
}

代码不长,但是可能需要时间理解。

讲讲malloc函数,malloc函数的作用是动态分配内存

每次输入数据前,我们就用p指向一个动态申请的新空间,然后存入数据。

程序的最后,我们用free()函数释放动态申请的空间,这样可以让我们的程序更安全。

我们学习c语言和c++应该追求最大程度地优化,排除可能出现的问题。