赞
踩
目录
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,但链表在逻辑上是连续的,顺序的,而数据元素的逻辑顺序是通过链表中的指针连接次序实现的。
看起来很麻烦,其实就是一个个的结点连起来的结构。如下图:
每一个结点的第一个data用来存放有效数据,第二个next用来存放下一个结点的地址
注意:最后一个结点的next存放的是NULL
链表只是在逻辑结构上是连续的,一个结点指向下一个结点,但是在物理存储结构上是不连续的。上图是为了方便大家理解,才用线条连接了结点。
- typedef int SListDataType;//对int进行重定义
- typedef struct SListNode //创建结点结构体
- {
- SListDataType a;
- struct SListNode* next;
- }SListNode;
学习数据结构主要就是对数据进行增删查改,在写出来一个链表后也要写一些函数接口方便对单链表的数据进行管理。写出下面的函数,用来创建和管理单链表。
- //新建一个结点
- SListNode* BuySListNode(SListDataType x);
- //显示单链表
- void SLPrint(SListNode* phead);
- //尾插
- void SLPushBack(SListNode** pphead, SListDataType x);
- //头插
- void SLPushFront(SListNode** pphead, SListDataType x);
- //尾删
- void SLPopBack(SListNode** pphead);
- //头删
- void SLPopFront(SListNode** pphead);
- //查找x结点地址
- SListNode* SLFind(SListNode* phead, SListDataType x);
- //在pos地址之前插入x
- void SLInsert(SListNode** pphead, SListNode* pos, SListDataType x);
- //在pos地址后边插入x
- void SLInsertAfter(SListNode* pos, SListDataType x);
- //删除pos地址结点
- void SLErase(SListNode** pphead, SListNode* pos);
- //删除pos地址之后的结点
- void SLEraseAfter(SListNode* pos);
- //销毁单链表
- void SLDestroy(SListNode** pphead);
利用malloc函数开辟一个结点,有效数据a存放x,指针next先存放NULL,最后返回新建结点的地址newnode。如果新结点为空即newnode==NULL会执行打印错误信息,退出程序。
- //开辟一个结点
- SListNode* BuySListNode(SListDataType x)
- {
- SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
- if (newnode == NULL)
- {
- perror("BuySListNode->malloc failed");
- exit(-1);
- }
- newnode->next = NULL;
- newnode->a = x;
- return newnode;
- }
把单链表中的每一个有效值打印在屏幕上。
- //显示单链表
- void SLPrint(SListNode* phead)
- {
- SListNode* cur = phead;
- while (cur != NULL)
- {
- printf("%d->", cur->a);
- cur = cur->next;
- }
- printf("NULL\n");
- }
- //尾插
- void SLPushBack(SListNode** pphead, SListDataType x)
- {
- assert(pphead);
- SListNode* newnode = BuySListNode(x);
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- else
- {
- SListNode* tail = *pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
- tail->next = newnode;
- }
- }
单链表的头插相对比较简单,在创建一个新结点后,只需要把新结点的next指针指向该单链表的头指针,然后再把单链表的头指针更新一下就OK了。
- //头插
- void SLPushFront(SListNode** pphead, SListDataType x)
- {
- assert(pphead);
- SListNode* newnode = BuySListNode(x);
- newnode->next = *pphead;
- *pphead = newnode;
- }
- //尾删
- void SLPopBack(SListNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- SListNode* tail = *pphead;
- SListNode* prev = NULL;
- while (tail->next != NULL)
- {
- prev = tail;
- tail = tail->next;
- }
- if (prev != NULL)
- {
- free(tail);
- prev->next = NULL;
- }
- else
- {
- free(tail);
- *pphead = NULL;
- }
- }
单链表的头删也是比较简单的,创建一个临时指针变量用来存放头结点下一个结点的地址,然后在把头结点释放点,再把临时变量的值,,赋给*pphead
- //头删
- void SLPopFront(SListNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- SListNode* tmp = (*pphead)->next;
- free(*pphead);
- *pphead = tmp;
- }
遍历整个链表,同时判断结点中的值是否为x,如果相等返回该结点地址,否则返回NULL
- //查找x结点地址
- SListNode* SLFind(SListNode* phead, SListDataType x)
- {
- assert(phead);
- SListNode* cur = phead;
- while (cur != NULL)
- {
- if (cur->a == x)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
断言pos和pphead不为空,然后再插入x,也得分两种情况:
- //在pos位置之前插入x
- void SLInsert(SListNode** pphead, SListNode* pos, SListDataType x)
- {
- assert(pos != NULL);
- assert(pphead);
- if (pos == *pphead)
- {
- SLPushFront(pphead, x);
- }
- else
- {
- SListNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
- SListNode* newnode = BuySListNode(x);
- newnode->next = pos;
- prev->next = newnode;
- }
- }
这个相较于前插就比较简单,首先断言pos不能为空,然后创建一个有效数值为x的新结点newnode,然后把pos位置的下一个结点的地址放到新结点newnode的next里去,然后再把newnode的地址存放到pos的next指针中。
- //在pos位置后边插入x
- void SLInsertAfter(SListNode* pos, SListDataType x)
- {
- assert(pos);
- SListNode* newnode = BuySListNode(x);
- newnode->next = pos->next;
- pos->next = newnode;
- }
三个断言不用说了
- //删除pos地址结点
- void SLErase(SListNode** pphead, SListNode* pos)
- {
- assert(pphead);
- assert(*pphead);
- assert(pos);
- SListNode* cur = *pphead;
- if (cur == pos)
- {
- SListNode* newHead = (*pphead)->next;
- free(*pphead);
- *pphead = newHead;
- }
- else
- {
- while (cur->next != pos)
- {
- cur = cur->next;
- }
- cur->next = pos->next;
- free(pos);
- }
- }
删除pos位置后的结点,先创建临时指针变量用来存放pos位置后的结点的地址,然后再把临时指针变量赋给pos结点的next
- //删除pos地址之后的结点
- void SLEraseAfter(SListNode* pos)
- {
- assert(pos != NULL);
- assert(pos->next != NULL);
- SListNode* posNext = pos->next;
- pos->next = posNext->next;
- free(posNext);
-
- }
如果单链表本身就为空直接返回,如果不为空就创建两个指针变量用来存放当前结点cur和当前结点的下一个结点curNext,然后释放当前结点cur,再把下一个结点地址curNext赋值给当前结点cur
- //销毁单链表
- void SLDestroy(SListNode** pphead)
- {
- assert(pphead);
- if (*pphead)
- return;
- SListNode* cur = *pphead;
- SListNode* curNext = NULL;
- while (cur != NULL)
- {
- curNext = cur->next;
- free(cur);
- cur = curNext;
- }
- }
包含头文件、函数声明、结构体定义等
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
-
- typedef int SListDataType;
- typedef struct SListNode
- {
- SListDataType a;
- struct SListNode* next;
- }SListNode;
-
-
- //新建一个结点
- SListNode* BuySListNode(SListDataType x);
- //显示单链表
- void SLPrint(SListNode* phead);
- //尾插
- void SLPushBack(SListNode** pphead, SListDataType x);
- //头插
- void SLPushFront(SListNode** pphead, SListDataType x);
- //尾删
- void SLPopBack(SListNode** pphead);
- //头删
- void SLPopFront(SListNode** pphead);
- //查找x结点地址
- SListNode* SLFind(SListNode* phead, SListDataType x);
- //在pos地址之前插入x
- void SLInsert(SListNode** pphead, SListNode* pos, SListDataType x);
- //在pos地址后边插入x
- void SLInsertAfter(SListNode* pos, SListDataType x);
- //删除pos地址结点
- void SLErase(SListNode** pphead, SListNode* pos);
- //删除pos地址之后的结点
- void SLEraseAfter(SListNode* pos);
- //销毁单链表
- void SLDestroy(SListNode** pphead);
对单链表相关函数的实现
- #include"SList.h"
-
-
- //开辟一个节点
- SListNode* BuySListNode(SListDataType x)
- {
- SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
- if (newnode == NULL)
- {
- perror("BuySListNode->malloc failed");
- exit(-1);
- }
- newnode->next = NULL;
- newnode->a = x;
- return newnode;
- }
-
-
- //显示单链表
- void SLPrint(SListNode* phead)
- {
- SListNode* cur = phead;
- while (cur != NULL)
- {
- printf("%d->", cur->a);
- cur = cur->next;
- }
- printf("NULL\n");
- }
-
-
- //尾插
- void SLPushBack(SListNode** pphead, SListDataType x)
- {
- assert(pphead);
- SListNode* newnode = BuySListNode(x);
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- else
- {
- SListNode* tail = *pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
- tail->next = newnode;
- }
- }
-
-
- //头插
- void SLPushFront(SListNode** pphead, SListDataType x)
- {
- assert(pphead);
- SListNode* newnode = BuySListNode(x);
- newnode->next = *pphead;
- *pphead = newnode;
- }
-
-
- //尾删
- void SLPopBack(SListNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- SListNode* tail = *pphead;
- SListNode* prev = NULL;
- while (tail->next != NULL)
- {
- prev = tail;
- tail = tail->next;
- }
- if (prev != NULL)
- {
- free(tail);
- prev->next = NULL;
- }
- else
- {
- free(tail);
- *pphead = NULL;
- }
- }
-
-
- //头删
- void SLPopFront(SListNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- SListNode* tmp = (*pphead)->next;
- free(*pphead);
- *pphead = tmp;
- }
-
-
- //查找节点地址
- SListNode* SLFind(SListNode* phead, SListDataType x)
- {
- assert(phead);
- SListNode* cur = phead;
- while (cur != NULL)
- {
- if (cur->a == x)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
-
- //在pos之前插入x
- void SLInsert(SListNode** pphead, SListNode* pos, SListDataType x)
- {
- assert(pos != NULL);
- assert(pphead);
- if (pos == *pphead)
- {
- SLPushFront(pphead, x);
- }
- else
- {
- SListNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
- SListNode* newnode = BuySListNode(x);
- newnode->next = pos;
- prev->next = newnode;
- }
- }
-
-
- //在pos后边插入x
- void SLInsertAfter(SListNode* pos, SListDataType x)
- {
- assert(pos);
- SListNode* newnode = BuySListNode(x);
- newnode->next = pos->next;
- pos->next = newnode;
- }
-
-
- //删除pos位置节点
- void SLErase(SListNode** pphead, SListNode* pos)
- {
- assert(pphead);
- assert(*pphead);
- assert(pos);
- SListNode* cur = *pphead;
- if (cur == pos)
- {
- SListNode* newHead = (*pphead)->next;
- free(*pphead);
- *pphead = newHead;
- }
- else
- {
- while (cur->next != pos)
- {
- cur = cur->next;
- }
- cur->next = pos->next;
- free(pos);
- }
- }
-
-
- //删除pos之后的节点
- void SLEraseAfter(SListNode* pos)
- {
- assert(pos != NULL);
- assert(pos->next != NULL);
- SListNode* posNext = pos->next;
- pos->next = posNext->next;
- free(posNext);
-
- }
-
- void SLDestroy(SListNode** pphead)
- {
- if (*pphead)
- return;
- SListNode* cur = *pphead;
- SListNode* curNext = NULL;
- while (cur != NULL)
- {
- curNext = cur->next;
- free(cur);
- cur = curNext;
- }
- }
对单链表测试,调整
- #include"SList.h"
-
- void test1()
- {
- SListNode* plist = NULL;
- SLPushBack(&plist, 1);
- SLPushBack(&plist, 2);
- SLPushBack(&plist, 3);
- SLPushBack(&plist, 5);
- SLPushBack(&plist, 6);
- SLPushBack(&plist, 7);
- SLPushBack(&plist, 8);
- SLPushBack(&plist, 9);
- SListNode* ret = SLFind(plist, 1);
- SLEraseAfter(ret);
- //for (int i = 1; i <= 4; i+=2)
- //{
- // SLPrint(plist);
- //
- // //SLErase(&plist, ret);
- // //SLInsertAfter(ret, 88);
- // //printf("%d = %p\n", i, ret);
- //}
- SLPrint(plist);
- }
- int main()
- {
- test1();
-
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。