单链表概述
单链表
线性表的链式存储是指用组任意的存储单元(可以连续,也可以不连续)存储线性表中的数据元素。数据元素在存储空间中表示时通常称为结点。因为数据元素可能不连续,为了能够反映数据元素之间的相邻逻辑关系,每个结点不仅要存放数据元素本身,还需要一些额外的存储空间,用于存放和它有关系的数据元素的地址,即需要存放指向其他元素的指针。我们称指向第一个结点的指针 为头指针,一但知道头指针,就可以沿着指针依次访问其他数据元素。
单链表中每个结点由两部分组成:数据域和指针域。数据域用于存放数据元素,指针域用于存放数据元素之间的关系,通常用于存放直接后继的地址。由于每个结点中只有一个,故称为单链表。
单链表的特征
1.单链表不要求逻辑上相邻的两个元素在物理位置上也相邻,因此不需要连续的存储空间。
2.单链表是顺序存储,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。
单链表结点的定义
对于每个链表结点,除了存放元素自身的信息外,还需要存放一个指向其后继的指针。描述如下:
typedef struct LinkList {
int data;
struct LinkList* next;
}LNode,*LinkLink;
单链表基本算法
单链表初始化
算法描述:传入单链表的头指针,分配相应的内存空间,将头指针指向NULL。
void InitLink(LinkLink &L){
L = (LinkLink)malloc(sizeof(LNode));
L->next = NULL;
return;}
单链表查空
算法描述:传入单链表,如果单链表不存在,输出“No exist!”,如果头指针的next指向NULL,输出“Empty”,反之,输出“No empty!”。
void CheckLinkEmpty(LinkLink L) {
if (L == NULL) {printf("No exist\n");}
else if (L->next == NULL) {printf("Empty!\n");}
else {printf("No empty!\n");}
return;}
单链表销毁
算法描述:定义一个LNode类型的指针p,指针指向传入的单链表头结点L,利用while循环判断L是否为空,不为空,p=L,L=L->next,然后释放p,以此循环,直到L为空,停止循环,链表被销毁。
void DestroyLink(LinkLink& L) {
LNode* p = L;
while (L)
{ p = L;
L = L->next;
free(p);}
printf("Destroy success!\n");}
单链表清空
算法描述:定义两个LNode类型的指针p,q。p指向首结点,利用while循环判断p是否为空,不为空让q指向p下一个结点,释放p,再让p等于q,以此循环,直到p为空,停止循环,让头指针L->next=NULL。
void ClearLink(LinkLink& L) {
LNode* p = (LinkLink)malloc(sizeof(LNode));
LNode* q = (LinkLink)malloc(sizeof(LNode));
p = L->next;
while (p) {
q = p->next;
free(p);
p = q;}
L->next = NULL;
printf("Clear success!\n");}
单链表求表长
算法描述:定义一个LNode类型的指针p指向单链表首结点,定义一个整数i=0。利用while循环判断p是否为空,如果不为空,p指向下一个结点,i加1,以此循环,直到p为空,返回i。
int LinkLength(LinkLink L) {
int i = 0;
LNode* p = L->next;
while (p) {
p = p->next;
i++;
}
printf("The length of the Link is %d\n", i);
return i;
}
单链表按值查找
(假定链表中存在该值)
算法描述:设查找的值为e,定义一个LNode类型的指针指向单链表首结点,定义一个整数i=0(用来计算结点位数)。利用while循环判断p是否为空,不为空,i加1,如果p->data等于e,则结束循环。反之,p指向下一个结点,以此循环。
void SearchLink(LinkLink L,int e) {
LNode* p = L->next;
int i =0 ;
while (p) {
i++;
if (p->data == e) {
printf("This is %d\n", i);
break;}
else {p = p->next;}}
return;
}
单链表按位查找
(假定位数存在)
算法描述:定义一个LNode类型的指针指向单链表头结点,定义一个整数i=0(用来计算结点位数)。利用while循环,如果i不等于位数r,则i++,p指向下一个结点,直到i等于r,输出p->data的值,结束循环。
void LookLink(LinkLink L,int r) {
LNode* p = L;
int i = 0;
while (i!=r)
{ i++;
p = p->next;}
printf("%d\n", p->data);
return;}
单链表添加结点
算法描述:定义两个LNode类型的指针p,q。p指向单链表头结点,另q->data等于e,利用for循环使p指向所需添加结点(r)的上一个结点(r-1),另q->next等于p->next。再让让p->next指向q。
void AddLink(LinkLink &L, int r, int e) {
LNode* p = L;
LNode *q= (LinkLink)malloc(sizeof(LNode));
q->data = e;
for (int i = 1; i < r; i++) {
p = p->next;
}
q->next = p->next;
p->next = q;
return;
}
单链表删除结点
算法描述:定义两个LNode类型的指针p,q。p指向单链表头结点。利用for循环使p指向所需删除结点(r)的上一个结点(r-1),另q->next等于p->next。再让让p->next指向删除结点下一个结点。释放q
void DeleteLink(LinkLink &L, int r) {
LNode* p = L;
LNode* q = (LinkLink)malloc(sizeof(LNode));
for (int i = 1; i < r; i++) {
p = p->next;
}
q->next = p->next;
p->next = p->next->next;
free(q);
return;
}
两种创建单链表的方法
头插法
算法描述:初始化单链表L,假定创造n个结点,利用for循环,每次循环,定义一个LNode的指针p,输入p->data的值,使p->next=L->next。L->next指向p。利用头插法输入{1,2,3}则会储存为{3,2,1}。
void CreateLinkHead(LinkLink& L, int n) {
InitLink(L);
for (int i = 0; i < n; i++) {
LNode *p= (LinkLink)malloc(sizeof(LNode));
scanf_s("%d", &(p->data));
p->next = L->next;
L->next = p;}
return;}
尾插法
算法描述:初始化单链表L,假定创造n个结点,定义一个LinkList的指针r指向头结点,利用for循环,每次循环,定义一个LNode的指针p,使p->next=NULL。输入p->data的值。让r->next指向p。r指向p。利用尾插法输入{1,2,3}则会储存为{1,2,3}。
void CreateLinkTail(LinkLink& L, int n) {
InitLink(L);
LinkList* r = (LinkLink)malloc(sizeof(LNode));
r = L;
for (int i = 0; i < n; i++) {
LNode* p= (LinkLink)malloc(sizeof(LNode));
p->next = NULL;
scanf_s("%d", &(p->data));
r->next = p;
r = p;
}
return;
}
调试
利用尾插法创建一个带头结点的9结点单链表,输入{9,8,7,6,5,4,3,2},进行一系列操作调试。
int main() {
LinkLink List;
CreateLinkTail(List, 8);
CheckLinkEmpty(List);
int a = LinkLength(List);
SearchLink(List, 6);
LookLink(List,5);
DeleteLink(List, 4);
a = LinkLength(List);
ClearLink(List);
CheckLinkEmpty(List);
DestroyLink(List);
CheckLinkEmpty(List);
return 0;
}
结果图: