有余顺序表在不断地开辟空间和空间转移会有一定的损耗,因此链表应运而生,但是在这里我们只讲解单链表虽然单链表也有一定的缺陷但是可以为之后的学习进行初步的了解便于后续的学习在这里我们首先介绍单链表得构成 ,我们使用结构体来创造单链表基本原理如下:
typedef int SListType;
struct SList {
SListType date;
struct SList* next;
};
我们在结构体中让上一个结构体存储下一个结构体的地址,每一个部分称之为节点,在每一个节点中存储一个我们需要的实际值,并且存储下一个节点的地址这样我们可以通过使用下一个节点的地址访问下一个节点的内容,在这里我们有一个逻辑图这个逻辑图只是便于我们理解单链表的基本原理:
这种方式能够使我们更加理解链表的使用原理,我们还有第二张图它可以在逻辑图的基础上加深我们对链表的印象:
基本原理可以简要概括为在上一个节点保存着下一个节点的地址最后一个节点保存的地址为空,这样可以判断是否是最后一个节点。
对于单链表的基本原理就是如此那么我们接下来介绍单链表的使用我们先从最简单的遍历开始:
void SListPrint(SList* phead) {
SList* temp = phead;
while (temp != NULL) {
cout << temp->date << " ";
temp = temp->next;
}
}
在这里需要特别说明由于单链表是单向的因此无法像顺序表那样可以直接访问其中的任意一个元素因此我们只能一个一个的进行寻找我们想要寻求的目标(在插入,删除等中会用到)
如图我们可以看出由于单链表的结束方式是节点中存储的地址是否为空,因此我们可以利用这个方法进行遍历操作,在图中 temp 就相当于 phead 在while循环中,由于单链表不管有没有节点都需要一个指针起到头作用如果链表中没有元素那么temp就为NULL;反之则指向第一个元素,在图中没打印一个节点数据后就将temp指向下一个节点 ,直至成为尾节点,由于尾节点的指向为空 此时temp的指向也为NULL,因此循环停止遍历结束,跳出遍历函数。
以上就是我们对单链表的简要理解和遍历方法,下面我们来介绍单链表的其他使用方法。
1,尾插法
void SListPush_back(SList** pphead, SListType x) {
SList* NewNode = (SList*)malloc(sizeof(SList));
if (NewNode == NULL) {
cout << " NewNode is NULL , malloc fail" << endl;
exit(-1);
}
NewNode->date = x;
NewNode->next = NULL;
if (*pphead == NULL) {
*pphead = NewNode;
}
else {
SList* tall = *pphead;
while (tall->next != NULL) {
tall = tall->next;
}
tall->next = NewNode;
}
}
在这里我们讲解一下大多数同学都容易迷惑的一个点在这个函数中我们为什么要使用二级指针?
在上面我们说了,每一个单链表都需要一个开头(头结点)我们要插入一个节点是不是要改变这个头结点的指向,既然改变了指向我们就要传地址,但是如下:
SList* plist = NULL;
SListPush_back(plist, 10);
在这里有这样一个疑问我们传递的已经是地址了,但是此地址非彼地址这个地址仅仅只是指针本身的