赞
踩
目录
为什么会有链表?
我们都有顺序表来存储数据了,
因为顺序表是有缺陷的:
1. 中间头部插入删除数据,需要挪动数据,效率低下。
2. 空间不够需要扩容,扩容会有一定的消耗,也可能会造成空间的浪费。
这时候,我们就要用到链表。
链表是一种物理存储结构上非连续、非顺序的存储结构,
数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
如下图:
基本结构:
- #pragma once
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
-
- typedef int SLDataType;
-
- typedef struct SListNode
- {
- SLDataType data;
- struct SListNode* next;
- }SLNode;
-
- //打印链表
- void SLPrint(SLNode* phead);
-
- //尾插
- void SLPushBack(SLNode** pphead, SLDataType x);
-
- //头插
- void SLPushFront(SLNode** pphead, SLDataType x);
-
- //尾删
- void SLPopBack(SLNode** ppheadx);
-
- //头删
- void SLPopFront(SLNode** pphead);
-
- //查找
- SLNode* SLFind(SLNode* phead, SLDataType x);
-
- //插入
- void SLInsert(SLNode** phead, SLNode* pos, SLDataType x);
-
- //删除
- void SLErase(SLNode** phead, SLNode* pos);
-
- //从pos后面插入
- void SLInsertAfter(SLNode* pos, SLDataType x);
-
- //从pos后面删除
- void SLEraseAfter(SLNode* pos);
- //建立一个新节点(重复操作写成函数复用)
- SLNode* BuyNewNode(SLDataType x)
- {
- //malloc一个链表节点大小的空间
- SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
-
- //检查
- if (newnode == NULL)
- {
- perror("malloc::fail");
- return;
- }
-
- //赋值
- newnode->data = x;
- newnode->next = NULL;
-
- return newnode;
- }
- //尾插
- void SLPushBack(SLNode** pphead, SLDataType x)
- {
- //检查二级指针pphead地址是否为空
- //方便检查是否传空指针了
- assert(pphead);
-
- //创建节点
- SLNode* newnode = BuyNewNode(x);
-
- //如果链表为空
- if (*pphead == NULL)
- {
- *pphead = newnode;
- }
- else//如果链表不为空
- {
- //找尾
- SLNode* tail = *pphead;
- while (tail->next != NULL)
- {
- tail = tail->next;
- }
-
- //尾插
- tail->next = newnode;
- }
- }
- //头插
- void SLPushFront(SLNode** pphead, SLDataType x)
- {
- //检查二级指针pphead地址是否为空
- //方便检查是否传空指针了
- assert(pphead);
-
- //创建节点
- SLNode* newnode = BuyNewNode(x);
-
- //头插
- newnode->next = *pphead;
- *pphead = newnode;
- }
- //尾删
- void SLPopBack(SLNode** pphead)
- {
- //检查二级指针pphead地址是否为空
- //方便检查是否传空指针了
- assert(pphead);
- //检查链表是否为空
- assert(*pphead);
-
- //头删的情况(链表只有一个数据)
- if ((*pphead)->next == NULL)
- {
- free(*pphead);
- *pphead = NULL;
- }
- else
- {
- //找尾
- SLNode* tail = *pphead;
- while (tail->next->next != NULL)
- {
- tail = tail->next;
- }
-
- //尾删
- free(tail->next);
- tail->next = NULL;
- }
- }
- //头删
- void SLPopFront(SLNode** pphead)
- {
- //检查二级指针pphead地址是否为空
- //方便检查是否传空指针了
- assert(pphead);
- //检查链表是否为空
- assert(*pphead);
-
- //头删
- SLNode* cur = (*pphead)->next;
- free(*pphead);
- *pphead = NULL;
- *pphead = cur;
- }
- //查找
- SLNode* SLFind(SLNode* phead, SLDataType x)
- {
- //创建指针遍历链表
- SLNode* cur = phead;
-
- //查找
- while (cur)
- {
- if (cur->data == x)
- {
- return cur;
- }
- cur = cur->next;
- }
-
- return NULL;
- }
- //插入
- void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
- {
- //检查查找的地址是否为空
- assert(pos);
-
- //pos的位置
- if (pos == *pphead)
- {
- SLPushFront(pphead, x);
- }
- else//在链表中间
- {
- SLNode* prev = *pphead;
-
- //查找pos对应位置
- while (prev->next != pos)
- {
- prev = prev->next;
- }
-
- //插入
- SLNode* newnode = BuyNewNode(x);
- prev->next = newnode;
- newnode->next = pos;
- }
- }
- //删除
- void SLErase(SLNode** pphead, SLNode* pos)
- {
- //检查二级指针pphead地址是否为空
- //方便检查是否传空指针了
- assert(pphead);
-
- //检查查找的地址是否为空
- assert(pos);
-
- //检查链表是否为空(这里其实不断言也可以)
- assert(*pphead);
-
- //头删的情况
- if (*pphead == pos)
- {
- SLPopFront(pphead);
- }
- else
- {
- //查找
- SLNode* prev = *pphead;
- while (prev->next != pos)
- {
- prev = prev->next;
- }
-
- //删除
- prev->next = pos->next;
- free(pos);
- pos = NULL;
- }
- }
- //从pos后面插入
- void SLInsertAfter(SLNode* pos, SLDataType x)
- {
- //检查查找的地址是否为空
- assert(pos);
-
- //创建节点
- SLNode* newnode = BuyNewNode(x);
-
- //再pos后面插入
- newnode->next = pos->next;
- pos->next = newnode;
- }
- //从pos后面删除
- void SLEraseAfter(SLNode* pos)
- {
- //检查查找的地址和要删除的地址是否为空
- assert(pos);
- assert(pos->next);
-
- //在pos后面删除,prev记住要删除的节点,然后free
- SLNode* prev = pos->next;
- pos->next = prev->next;
- free(pos->next);
- prev = NULL;
- }
这就是单链表的基本框架和接口了,
如果感兴趣,你也可以使用接口函数玩一玩。
但是链表是有缺陷的,
我们可以看到,
1. 链表想要访问一个节点,就得遍历链表,
2. 链表的尾删也需要遍历链表,
3. 而链表的优势是头删很方便是O(1)。
我们就能跟顺序表比较一下,
1. 顺序表头插需要挪动数据是O(N),
2. 但是顺序表能随机访问。
以上就是本篇文章的内容了,感谢你的阅读。
如果喜欢本文的话,欢迎点赞和评论,写下你的见解。
如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。
之后我还会输出更多高质量内容,欢迎收看。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。