赞
踩
目录
前言
之前我们了解了数据结构中线性表的顺序表的知识,今天我们来了解线性表中链表的知识。
- //SList.h
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
-
- //打印单链表的内容
- void SLTPrint(SLTNode* phead);
-
- //头部插⼊删除/尾部插⼊删除
- void SLTPushBack(SLTNode** pphead, SLTDataType x);
- void SLTPushFront(SLTNode** pphead, SLTDataType x);
- void SLTPopBack(SLTNode** pphead);
- void SLTPopFront(SLTNode** pphead);
-
- //查找
- SLTNode* SLTFind(SLTNode** pphead, SLTDataType x);
- //在指定位置之前插⼊数据
- void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
- //删除pos节点
- void SLTErase(SLTNode** pphead, SLTNode* pos);
- //在指定位置之后插⼊数据
- void SLTInsertAfter(SLTNode* pos, SLTDataType x);
- //删除pos之后的节点
- void SLTEraseAfter(SLTNode* pos);
- //销毁链表
- void SListDesTroy(SLTNode** pphead);
以上是我们单链表的主要接口,同时我们要定义一个单链表的结构:
- //Slist.h
-
- typedef int SLTDataType;//存放数据的类型
-
- typedef struct SListNode {
- SLTDataType data;
- struct SListNode* next;//下一个节点的地址
- }SLTNode;
- void SLTPrint(SLTNode* phead)
- {
- SLTNode* pcur = phead;
- while (pcur)
- {
- printf("%d->", pcur->data);
- pcur = pcur->next;
- }
- printf("NULL");
- }
通过pcur来实现对整个链表的遍历,但最后一个节点时,此时pucr->next=NULL,再赋值给pucr,所以跳出循环。然后每次循环打印每个节点中的数据。
对于插入操作,我们需要一个新的节点:
- //新的节点
- SLTNode* SLTBuyNode(SLTDataType x) {
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- if (newnode == NULL) {
- perror("malloc fail!");
- exit(1);
- }
- newnode->data =x;//节点数据为x
- newnode->next = NULL;///指针变量⽤保存下⼀个节点的地址为空
-
- return newnode;
- }
- void SLTPushBack(SLTNode** pphead, SLTDataType x) {
- assert(pphead);
- SLTNode* newnode=SLTBuyNode(x);//要插入新的节点
-
- if (*pphead == NULL) {//如果链表为空
- *pphead = newnode;//头节点为新节点
- return;
- }
- SLTNode* pucr = *pphead;//pucr遍历链表
- while (pucr->next)//如果为最后一个节点
- {
- pucr = pucr->next;//遍历
- }
- pucr->next = newnode;//最后一个节点的next为新节点
- }
尾插法就是遍历整个链表,找到最后一个节点,然后再插入同时要考虑链表为空的情况。
- void SLTPushFront(SLTNode** pphead, SLTDataType x) {
- assert(pphead);
- SLTNode* newnode = SLTBuyNode(x);
- newnode->next = *pphead;//把新节点的下一个节点设为以前的头节点
- *pphead = newnode;//头节点变为新节点
-
- }
头插法比尾插相比更加快速,因为不用遍历整个链表。
- void SLTPopBack(SLTNode** pphead) {
- assert(pphead);
- assert(*pphead);//链表不为空
- if ((*pphead)->next == NULL) {//只有一个节点
- free(*pphead);
- *pphead = NULL;
- return;
- }
- SLTNode* ptail = *pphead;//遍历整个链表
- SLTNode* prev = NULL;//遍历时前一个节点
- while (ptail->next != NULL) {//最后一个节点
- prev = ptail;
- ptail = ptail->next;
- }
- prev->next = NULL;//尾删
- free(ptail);//释放最后一个节点
- ptail = NULL;
- }
尾删与尾插一样,都是遍历整个链表,找到最后一个节点,只不过操作不一样。
- void SLTPopFront(SLTNode** pphead) {
- assert(pphead);
- assert(*pphead);//链表不为空
- SLTNode* ptail = *pphead;
- *pphead = ptail->next;//头节点为下一个节点
- free(ptail);//释放头节点
- ptail = NULL;
-
- }
我们需要一个指针来存放以前头节点的地址,不然到时候释放找不到地址了。
- SLTNode* SLTFind(SLTNode** pphead, SLTDataType x) {
- assert(pphead);
- SLTNode* pucr =* pphead;//遍历
- while (pucr) {//直到最后一个节点
- if (pucr->data == x) {
- return pucr;//找到了返回节点
- }
- pucr = pucr->next;
- }
- return NULL;//没找到返回空
- }
找到了我们返回的是SLTNode*的节点类型。
- void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {
- assert(pphead);
- assert(pos);//节点不为空
- assert(*pphead);//节点不为空了,链表也不能为空
-
- SLTNode* newNode=SLTBuyNode(x);//插入的新的节点
- if (pos == *pphead) {//在第一个节点插入
- SLTPushFront(pphead, x);//调用头插操作
- return;
- }
- SLTNode* prev = *pphead;//遍历
- while(prev->next != pos){//直到找到了目标节点之前的节点
- prev = prev->next;
- }
- //修改对应的指针连接
- prev->next = newNode;
- newNode->next = pos;
- }
如图:
- void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
- assert(pos);
- SLTNode* newNode = SLTBuyNode(x);
-
- //直接修改pos后的节点链接
- newNode->next = pos->next;
- pos->next = newNode;
- }
- void SLTErase(SLTNode** pphead, SLTNode* pos) {
- assert(pphead);
- assert(pos);//删除节点不为空
- assert(*pphead);//链表不为空
- SLTNode* prev = *pphead;
- if (prev == pos) {//如果删除头节点
- SLTPopFront(pphead);//调用头删
- return;
- }
- while (prev->next != pos) {//找到删除前的节点
- prev = prev->next;
- }
- //删除节点之前的节点链接到删除节点之后的节点
- prev->next = pos->next;
- //释放删除节点
- free(pos);
- pos = NULL;
- }
我们要注意不能先释放,不然找不到pos的下一个节点
- void SListDesTroy(SLTNode** pphead) {
- assert(pphead);
- assert(*pphead);
-
- SLTNode* pucr = *pphead;
- while (pucr) {//循环销毁
- SLTNode* next = pucr->next;
- free(pucr);
- pucr =next;
- }
- *pphead = NULL;
-
- }
由于每个节点都是我们动态开辟出来的,所以我们要进行依次的销毁
Slist.h
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
-
- typedef int SLTDataType;
-
- typedef struct SListNode {
- SLTDataType data;
- struct SListNode* next;
- }SLTNode;
-
- //打印单链表的内容
- void SLTPrint(SLTNode* phead);
-
- //头部插⼊删除/尾部插⼊删除
- void SLTPushBack(SLTNode** pphead, SLTDataType x);
- void SLTPushFront(SLTNode** pphead, SLTDataType x);
- void SLTPopBack(SLTNode** pphead);
- void SLTPopFront(SLTNode** pphead);
-
- //查找
- SLTNode* SLTFind(SLTNode** pphead, SLTDataType x);
- //在指定位置之前插⼊数据
- void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
- //删除pos节点
- void SLTErase(SLTNode** pphead, SLTNode* pos);
- //在指定位置之后插⼊数据
- void SLTInsertAfter(SLTNode* pos, SLTDataType x);
- //删除pos之后的节点
- void SLTEraseAfter(SLTNode* pos);
- //销毁链表
- void SListDesTroy(SLTNode** pphead);
Slist.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"Slist.h"
-
- //打印单链表的内容
- void SLTPrint(SLTNode* phead)
- {
- SLTNode* pcur = phead;
- while (pcur)
- {
- printf("%d->", pcur->data);
- pcur = pcur->next;
- }
- printf("NULL");
- }
-
- //新的节点
- SLTNode* SLTBuyNode(SLTDataType x) {
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- if (newnode == NULL) {
- perror("malloc fail!");
- exit(1);
- }
- newnode->data =x;
- newnode->next = NULL;
-
- return newnode;
- }
-
- //尾插
- void SLTPushBack(SLTNode** pphead, SLTDataType x) {
- assert(pphead);
- SLTNode* newnode=SLTBuyNode(x);
-
- if (*pphead == NULL) {
- *pphead = newnode;
- return;
- }
- SLTNode* pucr = *pphead;
- while (pucr->next)
- {
- pucr = pucr->next;
- }
- pucr->next = newnode;
- }
-
- //头插
- void SLTPushFront(SLTNode** pphead, SLTDataType x) {
- assert(pphead);
- SLTNode* newnode = SLTBuyNode(x);
- newnode->next = *pphead;
- *pphead = newnode;
-
- }
-
- //尾删
- void SLTPopBack(SLTNode** pphead) {
- assert(pphead);
- assert(*pphead);
- if ((*pphead)->next == NULL) {
- free(*pphead);
- *pphead = NULL;
- return;
- }
- SLTNode* ptail = *pphead;
- SLTNode* prev = NULL;
- while (ptail->next != NULL) {
- prev = ptail;
- ptail = ptail->next;
- }
- prev->next = NULL;
- free(ptail);
- ptail = NULL;
- }
-
- //头删
- void SLTPopFront(SLTNode** pphead) {
- assert(pphead);
- assert(*pphead);
- SLTNode* ptail = *pphead;
- *pphead = ptail->next;
- free(ptail);
- ptail = NULL;
-
- }
-
-
- //查找
- SLTNode* SLTFind(SLTNode** pphead, SLTDataType x) {
- assert(pphead);
- SLTNode* pucr =* pphead;
- while (pucr) {
- if (pucr->data == x) {
- return pucr;
- }
- pucr = pucr->next;
- }
- return NULL;
- }
-
- 在指定位置之前插⼊数据
- void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {
- assert(pphead);
- assert(pos);
- assert(*pphead);
-
- SLTNode* newNode=SLTBuyNode(x);
- if (pos == *pphead) {
- SLTPushFront(pphead, x);
- return;
- }
- SLTNode* prev = *pphead;
- while(prev->next != pos){
- prev = prev->next;
- }
- prev->next = newNode;
- newNode->next = pos;
- }
-
- //在指定位置之后插⼊数据
- void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
- assert(pos);
- SLTNode* newNode = SLTBuyNode(x);
-
- newNode->next = pos->next;
- pos->next = newNode;
- }
-
- //删除pos节点
- void SLTErase(SLTNode** pphead, SLTNode* pos) {
- assert(pphead);
- assert(pos);
- assert(*pphead);
- SLTNode* prev = *pphead;
- if (prev == pos) {
- SLTPopFront(pphead);
- return;
- }
- while (prev->next != pos) {
- prev = prev->next;
- }
- prev->next = pos->next;
- free(pos);
- pos = NULL;
- }
-
- //删除pos之后的节点
- void SLTEraseAfter(SLTNode* pos) {
- assert(pos);
- assert(pos->next);
-
- SLTNode* del = pos->next;
- pos->next = pos->next->next;
- free(del);
- del = NULL;
- }
-
- //销毁链表
- void SListDesTroy(SLTNode** pphead) {
- assert(pphead);
- assert(*pphead);
-
- SLTNode* pucr = *pphead;
- while (pucr) {
- SLTNode* next = pucr->next;
- free(pucr);
- pucr =next;
- }
- *pphead = NULL;
-
- }
test.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"Slist.h"
-
- void Slisttest1()
- {
- SLTNode * pf =NULL;
- SLTPushBack(&pf, 1);
- SLTPushBack(&pf, 2);
- SLTPushBack(&pf, 3);
- SLTPushBack(&pf, 4);
- SLTPushFront(&pf, 5);
- SLTPushFront(&pf, 7);
- SLTPushFront(&pf, 6);
- SLTPushFront(&pf, 8);
- //SLTPopFront(&pf);
- SLTNode *p=SLTFind(&pf,8);
- //在指定位置前后插入数据
- //SLTInsert(&pf, p, 0);
- //SLTInsertAfter(p, 5);
-
- //SLTErase(&pf, p);
- //SLTEraseAfter(p);
-
- SListDesTroy(&pf);
-
- SLTPrint(pf);
- }
-
-
- int main() {
- Slisttest1();
- return 0;
- }
-
上述文章我们讲了单链表的实现,希望对你有所帮助。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。