赞
踩
链表:按需申请释放
注意:链式结构在逻辑上是连续的,但是在物理上不一定连续。
- //signal list table 单链表
- //signal link table 单链表
- typedef int SLTataType;
- typedef struct SListNode //signal 单的
- {
- SLTataType data; //数据域
- struct SListNode* next; //指针域
- }SLTNode;
先来浅浅写一个打印函数
- void PrintSLT(SLTNode * phead)
- {
- SLTNode * cur = phead;
- while (cur == NULL)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
初始化链表
- int n;
- printf("请输入链表的长度:");
- scanf("%d", &n);
- printf("\n请依次输入每个结点的值:");
由于需要定义一个结构体指针来存放链表中第一个数据的地址,因此
SLTNode* plist = NULL;
使用for循环来完成链表数据的输入,但是由于后面的诸多函数(例如增删查改)均需要节点函数,因此我们先来写一个节点函数
- SLTNode* BuySListNode(SLTDataType x)
- {
- SLTNode* newnode =(SLTNode *) malloc(sizeof(SLTNode));
- if (newnode == NULL)
- {
- perror("malloc fail");
- exit(-1);
- }
- newnode->data = x;
- newnode->next = NULL;
- return newnode;
- }
完成节点函数后,利用for循环实现链表的连接:
- for (size_t i = 0; i < n; i++)
- {
- int val;
- scanf("%d", &val);
- SLTNode* newnode = BuySListNode(val);
- }
连接完成以后,我们考虑到,假如 plist==NULL;
- if (plist == NULL)
- {
- plist = newnode;
- }
但是假如plist != NULL,则有头插和尾插两种情况,但由于尾插情况较为复杂,而且我们现在是在初始化链表,因此我们先讨论头插情况。
物理图如下:
代码实现如下:
- newnode->next = plist;
- plist = newnode;
即代码汇总为
- for (size_t i = 0; i < n; i++)
- {
- int val;
- scanf("%d", &val);
- SLTNode* newnode = BuySListNode(val);
-
- // 头插
- newnode->next = plist;
- plist = newnode;
- }
那么问题来了,假如链表为空,需要对plist == NULL,进行分情况讨论吗,答案是不需要的,咱们看图说话。
整体代码如下:
- void PrintSLT(SLTNode* phead)
- {
- SLTNode * cur = phead;
- while (cur != NULL)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
-
- SLTNode* BuySListNode(SLTDataType x)
- {
- SLTNode* newnode =(SLTNode *) malloc(sizeof(SLTDataType));
- if (newnode == NULL)
- {
- perror("malloc fail");
- exit(-1);
- }
-
- newnode->data = x;
- newnode->next = NULL;
-
- return newnode;
- }
- void Test1()
- {
- int n;
- printf("请输入链表的长度:");
- scanf("%d", &n);
- printf("\n请依次输入每个结点的值:");
- SLTNode* plist = NULL;
- for (size_t i = 0; i < n; i++)
- {
- int val;
- scanf("%d",& val);
- SLTNode* newnode = BuySListNode(val);
-
- //头插
- newnode->next = plist;
- plist = newnode;
- }
-
- PrintSLT(plist);
-
- }
- int main()
- {
- Test1();
- return 0;
- }

运行如下:
现在来实行尾插 :
代码实现如下:
- void SLTPushBack(SLTNode* phead, SLTDataType x)
- {
- //phead是形参 plist是实参
- SLTNode* newnode = BuySListNode(x);
- while (phead->next)
- {
- phead = phead->next;
- }
- phead->next = newnode;
- }
运行如下:
现在又有一个新的问题来了,假如链表为空,那么要怎么插入呢?
此时就需要改变结构体指针,具体参考如下
- void SLTPushBack(SLTNode** phead, SLTDataType x)
- {
- //phead是形参 plist是实参
- SLTNode* newnode = BuySListNode(x);
- if (*phead == NULL)
- {
- *phead = newnode;
- }
- else
- {
- SLTNode* tail = *phead;
- while (tail->next)
- {
- tail = tail->next;
- }
- tail->next = newnode;
- }
- }

小tips:
1.改变结构体,需要用结构体指针
2.改变结构体指针, 需要用结构体指针的指针
头插尾插都写好了,我们再来写尾删头删
先来看结构图:
代码实现如下:
- void SLTPopBack(SLTNode** phead, SLTDataType x)
- {
- //1.空
- assert(*phead);//暴力检查
- //2.一个节点
- //3.一个以上节点
- if ((*phead)->next == NULL)
- {
- free(*phead);
- *phead = NULL;
- }
- else
- {
- //法一:
- SLTNode* tailPrev = NULL;//表示tail前的那个结构体
- SLTNode* tail = *phead;
- while (tail->next)
- {
- tailPrev = tail;
- tail = tail->next;
- }
- free(tail);
- tailPrev->next = NULL;
- //法二:
- SLTNode* tail = *phead;
- while (tail->next->next)
- {
- tail = tail->next;
- }
- free(tail->next);
- tail->next = NULL;
- }
- }

运行如下:
头删
代码实现如下:
- void SLTPopFront(SLTNode** phead)
- {
- //空
- assert(*phead);
-
- //非空
- SLTNode* newhead = (*phead)->next;
- free(*phead);
- *phead = newhead;
- }
运行如下:
接下来我们要进行:
//在pos位置插入x
void SLTInsert(SLTNode** phead, SLTNode* pos, SLTDataType x);
//在pos以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos位置
void SLTErase(SLTNode** phead, SLTNode* pos, SLTDataType x);
//删除pos的后一个位置
void SLTEraseAfter(SLTNode* pos, SLTDataType x);
欲知后事如何,请看下回分解,今天就先到这里了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。