概念:链表是一种物理存储结构上非连续、非顺序的存储结构,但链表在逻辑上是连续的,顺序的,而数据元素的逻辑顺序是通过链表中的指针连接次序实现的。
所谓单链表就是:单向链表,我们将链表中的每个元素称之为结点/节点,单链表中的每个节点是单向的,也就是说,我们无法直接获得某一结点的前面的第一个结点,即:前驱结点。
链表是由一个个结点组成的
单链表是一种常见的数据结构,用于存储和操作一系列的数据。它由节点组成,每个节点包含数据和指向下一个节点的指针。
- typedef int SLTDateType;
- typedef struct SListNode
- {
- SLTDateType Date;
- SListNode* next;
- }SListNode;
- //创建一个结点
- SLTNode* BuyListNode(SLTDateType x);
- //销毁单链表
- void SLTDestory(SLTNode** pphead);
- //单链表头插
- void SLTPushFront(SLTNode** pphead, SLTDateType x);
- //单链表尾插
- void SLTPushBack(SLTNode** pphead, SLTDateType x);
- //单链表头删
- void SLTPopFront(SLTNode** pphead);
- //单链表尾删
- void SLTPopBack(SLTNode** pphead);
- //单链表结点查找
- SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x);
- //单链表结点删除(删除pos位置的结点)
- void SLTErase(SLTNode** pphead, SLTNode* pos);
- //单链表结点插入(在pos之前插入)
- void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);
- // 单链表结点插入(在pos之后插入)
- void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x);
- // 单链表结点修改
- void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x);
- //打印单链表
- void PrintSLT(SLTNode * phead);
略
- #include"SLT.h"
-
- //建立一个新的结点
- //这是链表的缺点:经常需要使用malloc为newnode开辟空间
- SLTNode* BuyListNode(SLTDateType x)
- {
- //为什么要用malloc,是因为,如果在BuyListNode函数中SLTNode newnode,出了这个函数,newnode就被销毁了,
- //用malloc开辟空间,只要我们不主动释放这个空间,这个空间的数据一直存在,
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- //static SLTNode newnode;
- if (newnode == NULL)
- {
- perror("malloc:");
- exit(0);
- }
- newnode->data = x;
- newnode->next = NULL;
- return newnode;
- }
-
- //头插
- void SLTPushFront(SLTNode** pphead, SLTDateType x)
- {
- assert(pphead);//phead可能为NULL,但是pphead指向phead,不可能为空
- SLTNode* newnode = BuyListNode(x);
- //这里可不是newnode->next = (*pphead)->next;
- newnode->next = *pphead;
- *pphead = newnode;
- }
-
-
- //尾插
- //尾插特别容易出错,当链表中没有数据,即phead=NULL时,尾插就相当于头插了,此时需要改变phead的值
- void SLTPushBack(SLTNode** pphead, SLTDateType x)
- {
- assert(pphead);
- SLTNode* newnode = BuyListNode(x);
- //1、空
- //2、非空
- if (*pphead == NULL)
- {
- *pphead = newnode;
- //newnode->next = NULL;这一步是不需要的,newnode在建立的时候就默认newnode->next=NULL;
- }
- else
- {
- SLTNode* cur = *pphead;
- //这是单向链表的缺点,需要去找尾
- while (cur->next != NULL)
- {
- cur = cur->next;
- }
- cur->next = newnode;
- }
- }
-
- //头删
- void SLTPopFront(SLTNode** pphead)
- {
- assert(pphead);
- //温柔的检查
- if (*pphead == NULL)
- return;
- //暴力的检查
- assert(*pphead);
- SLTNode* head = *pphead;
- *pphead = (*pphead)->next;
- free(head);
- head = NULL;
- }
-
- //尾删
- void SLTPopBack(SLTNode** pphead)
- {
- assert(pphead);
- assert(*pphead);
- //1、一个结点
- //2、两个结点
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL;
- }
- else
- {
- SLTNode* cur = *pphead;
- while (cur->next->next)
- {
- cur = cur->next;
- }
- free(cur->next);
- cur->next = NULL;
- }
- }
- //打印单向链表
- void PrintSLT(SLTNode* phead)
- {
- SLTNode* cur = phead;
- while (cur != NULL)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL");
- printf("\n");
- }
-
- //单链表查找某个结点
- SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x)
- {
- SLTNode* find = phead;
- //别忘记分析找不到结点的情况
- while (find)
- {
- if (find->data == x)
- {
- return find;
- }
- find = find->next;
- }
- return NULL;
- }
-
- //删除pos位置的结点
- void SLTErase(SLTNode** pphead, SLTNode* pos)
- {
- assert(pphead);
- assert(pos);
- if (pos == *pphead)
- {
- SLTPopFront(pphead);
- }
- else
- {
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- //如果prev->next已经为空了,说明链表已经查完了,还没有查到pos
- //证明pos传入有误
- assert(prev->next);
- }
- prev->next = pos->next;
- free(pos);
- //pos = NULL;这个没必要,改变不了pos
- }
- }
- //单链表结点前插
- //一般插入结点都是在pos之前插入,但单链表在实现前插是比较困难的
- void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
- {
- assert(pphead);
- //头插
- if (pos == *pphead)
- {
- SLTPushFront(pphead, x);
- }
- //非头插
- else
- {
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- assert(prev->next);
- }
- SLTNode* newnode = BuyListNode(x);
- prev->next = newnode;
- newnode->next = pos;
- }
- }
- //单链表结点后插
- void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x)
- {
- SLTNode* cur = *pphead;
- while (cur != pos)
- {
- cur = cur->next;
- //防止pos传错了
- assert(cur);
- }
- SLTNode* newnode = BuyListNode(x);
- newnode->next = pos->next;
- pos->next = newnode;
- }
-
- // 单链表结点修改
- void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x)
- {
- SLTNode* cur = phead;
- while (cur != pos)
- {
- cur = cur->next;
- assert(cur);
- }
- pos->data = x;
- }
- //销毁链表
- void SLTDestory(SLTNode** pphead)
- {
- assert(pphead);
- SLTNode* cur = *pphead;
- //比cur->next!=NULL更好一些
- while (cur)
- {
- SLTNode* next = cur->next;
- free(cur);
- cur = next;
- }
- *pphead = NULL;
- }
更加详细的请看原文【数据结构】——单链表超详细介绍(独家介绍,小白必看!!!)-CSDN博客
❤️❤️❤️