「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。
1.1 单链表数据结构
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素,链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。数据结构如下:
typedef struct node {
int data;//代表数据域
struct LinkNode *next;//代表指针域,指向直接后继元素
}LinkNode;
如图1.1展示了一个单链表:
了解了单链表的数据结构,下面我们通过研究单链表的插入、查询引出其时间复杂度,最后再引出具体单链表的问题。我们先看一下插入过程。
1.2 单链表插入过程
我们先生成一个10、20、30这样的链表:
LinkNode* InitLinkNode(){
//创建一个头结点
LinkNode *p = (LinkNode *)malloc(sizeof(LinkNode));
//声明一个指针指向头结点,用于遍历链表
LinkNode *temp = p;
//生成链表
for (int i = 1; i < 40; i += 10) {
LinkNode *node = (LinkNode *)malloc(sizeof(LinkNode));
node->data = i;
a->next = NULL;
temp->next = a;
temp = temp->next;
}
return p;
}
生成的链表如图1.2:
然后我们插入一个数字25,我看一下过程是什么样的?
LinkNode* insert(LinkNode *p, int data){
LinkNode *temp = p;//创建临时结点temp
while(temp != NULL) {
if (temp->next == NULL || temp->next->data > data)
{
LinkNode *tempNode = (LinkNode *)malloc(sizeof(LinkNode));
tempNode->data = data;
tempNode->next = temp->next;
temp->next = tempNode;
break;
}
temp = temp->next;
}
return temp;
}
第一次对比过程,如图1.3,跟链表的第一个结点最对比,结果10小于25,往后进行对比,
第二次对比过程,如图1.4,跟链表的第二个结点做对比,结果20也小于25,继续往后对比,
第三次对比过程,如图1.5,跟链表第三个结点做对比,结果30大于25,那我们就找到了插入的位置在20和30之间,
最后我们把数字25插入到20和30之间,我们看一下最后的链表,如图1.6,我们插入过程的时间复杂度是O(N)。
1.3 单链表的查询过程
同样的,我们看想查找数字25,我看一下过程是什么样的?
int Find(LinkNode *p,int data){
LinkNode *temp = p;
while (temp != NULL) {
if (temp->next != NULL && temp->next->data == data) {
return 1;
}
temp = temp->next;
}
return -1;
}
查询第一次对比过程,如图1.7,25大于第一个结点10,往后对比,
查询第二次对比过程,如图1.8,25大于第二个结点20,继续往后对比,
查询第三次对比过程,如图1.9,25等于第三个结点25,返回。
我们通过程序得知,我们的查询的一个时间复杂度也是O(N)
1.4 单链表的问题
我们通过分析单链表的插入、查询的过程得知,它们的时间复杂度都是O(N),那假如我们想降低时间复杂度呢?很明显单链表已经不能满足我们的需求了,那我们要怎么做呢?