赞
踩
仙人有待乘黄鹤,海客无心随白鸥。 ——李白
目录
单链表是一种线性的数据结构,相较于顺序表,单链表进行数据操作的效率会优化很多。单链表使用任意一组存储单元来保存线性的数据,并不需要使用连续地址的存储位置,仅通过指针进行访问下一元素,。因此,单链表的物理结构并不要求像逻辑结构一样连续。
单链表的定义可以使用结构体完成
- typedef int SLTDataType;//数据类型
-
- typedef struct SListNode
- {
- SLTDataType data;
- struct SListNode* next;//指向结构体的下一个位置,使数据链式连接
- }SLTNode;
单链表作为一种链式数据存储结构,能实现的操作有查看数据(打印)、增加数据(头插尾插)、删除数据(头删尾删)、插入数据、查找特定数据、删除特定位置的数据等操作。
相较于由数组模拟的顺序表而言,结构体形成的单链表无需在意容量大小,并且在插入数据的时候也不用一次次遍历整个链表。
由单链表的逻辑结构可知,单链表是通过next指针指向下一个元素的,那么一个指针从头开始遍历整个链表一直到NULL,即可完成单链表的打印。话不多说,上代码
- void SLTPrint(SLTNode* phead)
- {
- SLTNode* cur = phead;//头指针
- //遍历链表打印
- while (cur)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
如何在原有链式结构上添加新数据?答案是看物理结构。那么到底怎么实现呢?答案还是看物理结构。
既然链表是由结构体实现的,那么对于一个要插入的数据data,我们首先要为它开辟一块结构体空间。
此时再来观察链表的物理结构,很显然我们只需改变箭头的方向(即next指向的位置)便可完成数据的插入。
上代码
- SLTNode* BuySLTNode(SLTDataType x)
- {
- //为新数据开辟空间
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- if (newnode == NULL)
- {
- perror("malloc fail");
- return NULL;//开辟失败
- }
- newnode->data = x;
- newnode -> next = NULL;
- return newnode;
- }
-
- void SLTPushBack(SLTNode** pphead, SLTDataType x)
- {
- assert(pphead);
- SLTNode* newnode = BuySLTNode(x);
- //case1:空链表
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- //case2:非空链表
- else
- {
- //找尾
- SLTNode* tail = *pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
- tail->next = newnode;
- }
- }
-
- void SLTPushFront(SLTNode** pphead, SLTDataType x)
- {
- assert(pphead);
- SLTNode* newnode = BuySLTNode(x);
- newnode -> next = *pphead;//头插
- *pphead= newnode;//换头
- }
有了上面头插尾插的经验,相信大家对头删尾删也有了初步的想法。没错,将next跳过下一个位置即可完成链表的删除,但是仍有一些细节需要注意。
特别注意的是,由于尾删时需要先找到尾节点的位置,如果我们直接将尾节点置为空,则会形成尾指针为野指针的现象,因此我们要找尾节点的上一个next并将其置为空。
看代码
- void SLTPopFront(SLTNode** pphead)
- {
- assert(*pphead);
- assert(pphead);
- SLTNode* first = *pphead;
- *pphead = first->next;
- free(first);
- first = NULL;
- }
-
- void SLTPopBack(SLTNode** pphead)
- {
- assert(*pphead);
- assert(pphead);
- //case1:一个节点
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL;
- }
- //case2:多个节点
- else
- {
- //找尾
- SLTNode* tail = *pphead;
- //尾节点的上一个节点的next置空 不然尾节点则为野指针
- while (tail->next->next != NULL)
- {
- tail = tail->next;
- }
- free(tail->next);
- tail -> next = NULL;
-
- }
- }
查找即简单遍历链表,与打印相似,在此不过多介绍,直接看代码吧。
- SLTNode* SListFind(SLTNode* phead, SLTDataType x)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- if (cur->data == x)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
对于给定的pos位置进行增删,原理与头尾的操作相似,但是如果pos在链表中间位置,则需调整pos位置的前一个的next,当然如果pos本身就是头尾,那其实与上面的操作无异。
- //pos位置插入
- void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
- {
- assert(pphead);
- assert(pos);
- if (pos == *pphead)
- {
- SLTPushFront(pphead, x);
- }
- else
- {
- //pos的前一个位置
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
- SLTNode* newnode = BuySLTNode(x);
- prev->next = newnode;
- newnode->next = pos;
- }
- }
-
- //pos位置删除
- void SListErase(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->next;
- free(pos);
- pos = NULL;
- }
- }
-
- //pos位置的后一个插入
- void SListInsertAfter(SLTNode* pos, SLTDataType x)
- {
- assert(pos);
- SLTNode* newnode = BuySLTNode(x);
- newnode->next = pos->next;
- pos->next = newnode;
- }
-
- //pos位置的后一个删除
- void SListEraseAfter(SLTNode* pos)
- {
- assert(pos);
- assert(pos->next);
- SLTNode* del = pos->next;
- pos->next = del->next;
- free(del);
- del = NULL;
- }
- //SList.h 头文件
- #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* SListFind(SLTNode* pead, SLTDataType x);
- void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
- void SListErase(SLTNode** pphead, SLTNode* pos);
- void SListInsertAfter(SLTNode* pos, SLTDataType x);
- void SListEraseAfter(SLTNode* pos);
- //Slist.c源文件
-
- #include "SList.h"
-
- void SLTPrint(SLTNode* phead)
- {
- SLTNode* cur = phead;
- //遍历链表打印
- while (cur)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
-
- SLTNode* BuySLTNode(SLTDataType x)
- {
- //开辟空间
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- if (newnode == NULL)
- {
- perror("malloc fail");
- return NULL;
- }
- newnode->data = x;
- newnode -> next = NULL;
- return newnode;
- }
-
- void SLTPushBack(SLTNode** pphead, SLTDataType x)
- {
- assert(pphead);
- SLTNode* newnode = BuySLTNode(x);
- //case1:空链表
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- //case2:非空链表
- else
- {
- //找尾
- SLTNode* tail = *pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
- tail->next = newnode;
- }
- }
-
- void SLTPushFront(SLTNode** pphead, SLTDataType x)
- {
- assert(pphead);
- SLTNode* newnode = BuySLTNode(x);
- newnode -> next = *pphead;//头插
- *pphead= newnode;//换头
- }
-
- void SLTPopBack(SLTNode** pphead)
- {
- assert(*pphead);
- assert(pphead);
- //case1:一个节点
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL;
- }
- //case2:多个节点
- else
- {
- //找尾
- SLTNode* tail = *pphead;
- //尾节点的上一个节点的next置空 不然尾节点则为野指针
- while (tail->next->next != NULL)
- {
- tail = tail->next;
- }
- free(tail->next);
- tail -> next = NULL;
-
- }
- }
-
- void SLTPopFront(SLTNode** pphead)
- {
- assert(*pphead);
- assert(pphead);
- SLTNode* first = *pphead;
- *pphead = first->next;
- free(first);
- first = NULL;
- }
-
- SLTNode* SListFind(SLTNode* phead, SLTDataType x)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- if (cur->data == x)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
-
- //pos位置插入
- void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
- {
- assert(pphead);
- assert(pos);
- if (pos == *pphead)
- {
- SLTPushFront(pphead, x);
- }
- else
- {
- //pos的前一个位置
- SLTNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
- SLTNode* newnode = BuySLTNode(x);
- prev->next = newnode;
- newnode->next = pos;
- }
- }
-
- //pos位置删除
- void SListErase(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->next;
- free(pos);
- pos = NULL;
- }
- }
-
- //pos位置的后一个插入
- void SListInsertAfter(SLTNode* pos, SLTDataType x)
- {
- assert(pos);
- SLTNode* newnode = BuySLTNode(x);
- newnode->next = pos->next;
- pos->next = newnode;
- }
-
- //pos位置的后一个删除
- void SListEraseAfter(SLTNode* pos)
- {
- assert(pos);
- assert(pos->next);
- SLTNode* del = pos->next;
- pos->next = del->next;
- free(del);
- del = NULL;
- }
本章到此就结束了,希望大家可以对单链表有一个清晰的认识。
(最近压力有些大,这几天有隐隐摆烂的痕迹,要从现在找回状态,加油!)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。