1.概述
单链表使是一种链式存储结构,链表中的数据以结点的方式表示.每个结点由数据域和指针域两部分构成.数据域存储链表的数据元素,指针域存储连接相邻结点的地址.
2.单链表基本组成
typedef struct linklist_t{
int data;
// 数据域.
struct linklist_t *next;
// 指针域.
}LinkList_T;
static LinkList_T *pHead;
// 头指针.
上述代码中我们定义了 pHead 头指针结点.这个结点并不包含实际的数据域,仅仅是为了我们更加方便的操作链表.
3.单链表基础操作
3.1创建单链表
创建单链表的整体思路是依托于pHead头结点,创建结点,并建立结点之间的相互关系.
/*
创建一个含有n个结点的单链表.
*/
int creatlist(int n)
{
LinkList_T *pTmp = NULL, *pEnd = NULL;
int i = 0;
pHead = (LinkList_T*)malloc(sizeof (LinkList_T));
if (NULL == pHead)
return -1;
pEnd = pHead;
/*
整体流程: pEnd指向了pHead头结点.
首次执行for循环时,设置pTmp的数据域,然后pEnd->next指向pTmp(即首结点).之后pEnd后移指向pTmp.
第二次执行pTmp时,pEnd指向的是第一个结点(不计算pHead),pEnd->next = pTmp;
即第一个结点的next指针指向新加入的结点.pEnd = pTmp;
pEnd再指向新加入的结点.
依次类推.即完成了链表的创建.
*/
for (i = 0;
i < n;
i++){
pTmp = (LinkList_T*)malloc(sizeof (LinkList_T));
pTmp->data = https://www.it610.com/article/i;
pEnd->next = pTmp;
pEnd = pTmp;
}
pEnd->next = NULL;
return 0;
}
3.2插入新结点
插入结点的思路是找到要插入的位置,先建立待插入结点与下一个结点的关系,然后再建立待插入结点与 上一个结点的位置关系(即断开插入之前的连接关系).
/*
在链表的第n个结点后面插入新的结点.
*/
int insertlist(int n, int num)
{
/*
整体思路:
1.遍历链表找到要插入的位置.
2.插入结点.
*/
LinkList_T *pTmp = NULL, *pNode = NULL;
int j = 0;
pTmp = pHead;
/*
遍历链表寻找插入位置.
*/
while (pTmp && (j < n)){
pTmp = pTmp->next;
j++;
}
/*
结点不存在.
*/
if (NULL == pTmp)
return -1;
pNode = (LinkList_T *)malloc(sizeof (LinkList_T));
if (NULL == pNode)
return -1;
/*
插入结点思路:
pNode->next = pTmp->next;
先连接后面的结点.
pTmp->next = pNode;
将前面的结点指向自己,即断开了前面结点与之前后面结点的连接.
*/
pNode->next = pTmp->next;
pNode->data = https://www.it610.com/article/num;
pTmp->next = pNode;
return 0;
}
3.3删除节点
删除结点的思路是找到待删除的结点,建立待删除结点的前一个结点与待删除结点的后一个结点之间的连接关系.然后删除待删除结点.
/*
删除单链表的第n个结点.
*/
int dellist(int n)
{
LinkList_T *pTmp = pHead;
LinkList_T *pPrv = pHead;
int j = 0;
/*
遍历链表寻找要删除的位置.
注意此时要保留待删除结点的前一个结点地址.
*/
while(pTmp && (j < n)){
pPrv = pTmp;
pTmp = pTmp->next;
j++;
}
if (NULL == pTmp)
return -1;
/*
思路:
1.获取到要删除的结点和前一个结点.
2.建立要删除的结点的后一个结点和其前一个结点的关系.
3.删除待删结点.
*/
pPrv->next = pTmp->next;
pTmp->next = pTmp;
free(pTmp);
return 0;
}
3.4修改链表数据
【算法与数据结构|C语言单链表实现增删改查】修改链表指定结点数据的思路是遍历链表找到待修改结点,修改数据域.
/*
修改链表第n个结点的数据域
*/
int changelist(int n, int num)
{LinkList_T *pTmp = NULL;
int j = 0;
pTmp = pHead;
/*
遍历链表找到修改项
*/
while(pTmp && (j < n)){
pTmp = pTmp->next;
j++;
}if (NULL == pTmp)
return -1;
/*
修改数据.
*/
pTmp->data = https://www.it610.com/article/num;
return 0;
}
3.5查询链表
/*
查询链表
*/
int querylist(void)
{
LinkList_T *pTmp = NULL;
int i = 0;
pTmp = pHead;
while(pTmp->next){
pTmp = pTmp->next;
i++;
printf ("第 %d 结点的值是 %d \r\n",i, pTmp->data);
}
printf ("\r\n");
return 0;
}
4.测试程序
int main(int argc, char **argv)
{
creatlist(5);
querylist();
insertlist(5, 8);
querylist();
changelist(2, 6);
querylist();
insertlist(2, 8);
querylist();
dellist(3);
querylist();
}
5测试结果
第 1 结点的值为 0
第 2 结点的值为 1
第 3 结点的值为 2
第 4 结点的值为 3
第 5 结点的值为 4 第 1 结点的值为 0
第 2 结点的值为 1
第 3 结点的值为 2
第 4 结点的值为 3
第 5 结点的值为 4
第 6 结点的值为 8 第 1 结点的值为 0
第 2 结点的值为 6
第 3 结点的值为 2
第 4 结点的值为 3
第 5 结点的值为 4
第 6 结点的值为 8 第 1 结点的值为 0
第 2 结点的值为 6
第 3 结点的值为 8
第 4 结点的值为 2
第 5 结点的值为 3
第 6 结点的值为 4
第 7 结点的值为 8 第 1 结点的值为 0
第 2 结点的值为 6
第 3 结点的值为 2
第 4 结点的值为 3
第 5 结点的值为 4
第 6 结点的值为 8
推荐阅读
- 数据结构|【数据结构】【王道】【线性表】无头结点单链表的实现及基本操作(可直接运行)
- 数据结构|MySQL主从复制详细介绍
- 数据结构|红黑树(RBTree)原理及实现
- 力扣|力扣打卡之最小栈
- MySQL零基础入门|MySQL 数据库基础知识(系统化一篇入门)
- scau|18937 阿克曼(Ackmann)函数
- 链表|数据结构与算法(环形链表,栈)
- dp|最近写过的dp题单(持续更新)
- 数据结构|递归算法简介