定义
线性表的链式存储方式称为单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。
为了实现数据元素之间的线性关系,所以每个结点中除了存储自身的值以外,还会存放一个指向后继的指针。
具体的代码如下:
typedef struct LNode{
int data;//结点的数据
LNode* Next;//指向下一结点的指针
}LNode,*LinkList;//前者为结点,后者为链表(只是两种不同表述方式)
操作
在单链表的具体实现中,有两种实现方式,一种是带头结点的单链表,一种是不带头结点的单链表。
两者的共同点在于,都有一个头指针用于指向链表的第一个结点。
两者的区别在于,带头结点的单链表会有一个头结点,这个头结点的Next指针指向单链表的第一个结点,所以头指针是指向头结点的;而不带头结点的单链表则是由头指针直接指向第一个结点。
因为带头结点的单链表在代码实现的时候更加简便,所以本文以带头结点的形式来实现单链表各种操作。
初始化
bool InitList(LinkList& L)
{
L = (LNode*)malloc(sizeof(LNode));//创建头结点
if (L == NULL)
{
cout << "内存不足分配失败!" << endl;
return false;
}
else
{
L->next = NULL;//初始化的链表中没有结点,所以指向NULL
return true;
}
}
在初始化时,要注意使用malloc函数的判空,因为使用malloc时可能会出现失败的情况,加入判空可以增加代码的健壮性。
结点前插
给定链表的一个结点,实现在此结点的前面插入一个结点,有两种实现方式。
第一,从头开始找到该结点的前驱结点实现插入(这种实现方式需要我们知道头指针,并且时间复杂度为O(n))
第二,原地前插
bool InsertPriorNode(LNode* p, int e) {
//在p结点前面插入元素e
if (p == NULL) {
//判断p结点是否为空,如果为空是不能前插的
return false;
}
LNode* L = (LNode*)malloc(sizeof(LNode));
if (L == NULL) {
cout << "内存分配失败" << endl;
return false;
}
else {
L->next = p->next;//新结点连入
p->next = L;//前链连接上新结点
L->data = p->data;//数据交换,实现前插
p->data = e;
return true;
}
}
在这种前插方式下,时间复杂度为O(1),而且不需要知道头指针
如果给定的是需要前插的不是值,而是结点,具体的实现代码如下:
bool Ins