赞
踩
目录
悟已往之不谏,知来者犹可追
创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免费的赞哟
问题:
1. 中间/头部的插入删除,时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
思考:如何解决以上问题呢?下面给出了链表的结构来看看。
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表 中的指针链接次序实现的 。
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
1. 单项或者双向
2. 带头或者不带头
3. 循环或者非循环
虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:
1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了,后面我们代码实现了就知道了。
下面我就来实现一下无头单向非循环链表~
这里我就具体实现一下接口~(SList.h)
- #define _CRT_SECURE_NO_WARNINGS
- #pragma once//避免头文件被多次引用
- #include<stdio.h>
- #include<assert.h>
- #include<stdlib.h>
- typedef int SListDataType;//便于改变数据类型
-
- //定义一个结构体类型的节点
- typedef struct SListNode
- {
- SListDataType data;
- struct SListNode* next;//存储下一个节点的地址
- }SListNode;
-
- //1. 新节点的创建
- SListNode* SListCreatNode(SListDataType x);
-
- //2. 打印单链表
- void PrintSList(SListNode* phead);
-
- //3. 头插
- void SListPushFront(SListNode** phead, SListDataType x);
-
- //4. 头删
- void SListPopFront(SListNode** phead);
-
- //5. 尾差
- void SListPushBack(SListNode** phead, SListDataType x);
-
- //6. 尾删
- void SListPopBack(SListNode** phead);
-
- //7. 查找元素X
- SListNode* SListFind(SListNode* phead, SListDataType x);
-
- //8. 在pos位置修改
- void SListModify(SListNode* pos, SListDataType x);
-
- //9. 在任意位置之前插入
- void SListInsert(SListNode** phead, SListNode* pos, SListDataType x);
-
- //10. 在任意位置删除
- void SListErase(SListNode** phead, SListNode* pos);
-
- //11. 销毁单链表
- void SListDestroy(SListNode** phead);

(1)代码实现
- //1. 新节点的创建
- SListNode* SListCreatNode(SListDataType x)
- {
- SListNode* NewNode= (SListNode*)malloc(sizeof(SListNode));//开辟空间
- if (NewNode == NULL)//判断空间是否开辟成功
- {
- perror("malloc fail");
- return NULL;
- }
- NewNode->data = x;//赋值
- NewNode->next = NULL;//置空
- return NewNode;
- }
(1)代码实现
- //2. 打印单链表
- void PrintSList(SListNode* phead)
- {
- if (phead == NULL)
- {
- printf("NULL");//如果链表没有元素就打印NULL
- return;
- }
- SListNode* cur = phead;
- //循环单链表打印
- while (cur != NULL)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }

(2) 复杂度分析
(1)代码实现
- //3. 头插
- void SListPushFront(SListNode** phead, SListDataType x)
- {
- assert(phead);
- SListNode* newnode =SListCreatNode(x);//创建一个新节点
- newnode->next =*phead;
- *phead = newnode;
- }
(2) 复杂度分析
(1)代码实现
- //4. 头删
- void SListPopFront(SListNode** phead)
- {
- assert(phead);
- assert(*phead);//如果没有数据就不用头删,并报错
- SListNode* cur = (*phead)->next;
- free(*phead);
- *phead = cur;
- }
(2) 复杂度分析
(1)代码实现
- //5. 尾插
- void SListPushBack(SListNode** phead, SListDataType x)
- {
- assert(phead);
- if (*phead == NULL)
- {
- *phead = SListCreatNode(x);//创建新节点并插入
- }
- else
- {
- SListNode* tail = *phead;
- while (tail->next != NULL)//找到尾节点
- {
- tail = tail->next;
- }
- tail->next = SListCreatNode(x);//创建新节点并插入
- }
- }

(2) 复杂度分析
(1)代码实现
- //6. 尾删
- void SListPopBack(SListNode** phead)
- {
- assert(phead);
- assert(*phead);//链表为空就不进行尾删
- SListNode* tail = *phead;
- if (tail->next == NULL)//如果链表就只有一个元素就进行头删
- {
- SListPopFront(phead);
- }
- else
- {
- while (tail->next->next != NULL)
- {
- tail = tail->next;
- }
- free(tail->next);
- tail->next = NULL;
- }
- }

(2) 复杂度分析
(1)代码实现
- //7. 查找元素X
- SListNode* SListFind(SListNode* phead, SListDataType x)
- {
- assert(phead);
- while (phead->next!=NULL)//注意最后一个节点是没有查找的
- {
- if (phead->data == x)
- return phead;
- phead = phead->next;
- }
- if (phead->data == x)
- return phead;//最后一个节点没有查找
- else
- return NULL;//没找到
- }
(2) 时间复杂度
(1)代码实现
-
- //8. 在pos位置修改
- void SListModify( SListNode* pos, SListDataType x)
- {
- assert(pos);
- pos->data = x;
- }
(2) 时间复杂度
(1)代码实现
- //9. 在任意位置之前插入
- void SListInsert(SListNode** phead, SListNode* pos, SListDataType x)
- {
- assert(phead);
- assert(*phead);
- if (pos==*phead)//如果pos位置刚好是第一个节点就进行头插
- {
- SListPushFront( phead,x);
- }
- else
- {
- SListNode* newnode = SListCreatNode(x);
- SListNode* cur = *phead;
- while (cur->next != pos)//找到pos前一个节点
- {
- cur = cur->next;
- }
- cur->next = newnode;
- newnode->next = pos;
- }
- }

(2) 复杂度分析
(1)代码实现
- //10. 在任意位置删除
- void SListErase(SListNode** phead, SListNode* pos)
- {
- assert(phead && *phead && pos);
- if (pos==*phead)//如果pos位置就是第一个节点就进行头删
- {
- SListPopFront(phead);
- }
- else
- {
- SListNode* cur = *phead;
- while (cur->next != pos)//找到pos前一个节点
- {
- cur = cur->next;
- }
- cur->next = pos->next;
- free(pos);
- }
- }

(2) 复杂度分析
(1)代码实现
- //11. 销毁单链表
- void SListDestroy(SListNode** phead)
- {
- assert(*phead && phead);
- SListNode* cur = *phead;
- while (cur!= NULL)
- {
- SListNode* tmp = cur->next;
- free(cur);
- cur = tmp;
- }
- *phead = NULL;
- }
(2) 复杂度分析
SList.c
- #define _CRT_SECURE_NO_WARNINGS
-
- #include"SList.h"
-
- //1. 新节点的创建
- SListNode* SListCreatNode(SListDataType x)
- {
- SListNode* NewNode= (SListNode*)malloc(sizeof(SListNode));//开辟空间
- if (NewNode == NULL)//判断空间是否开辟成功
- {
- perror("malloc fail");
- return NULL;
- }
- NewNode->data = x;//赋值
- NewNode->next = NULL;//置空
- return NewNode;
- }
-
- //2. 打印单链表
- void PrintSList(SListNode* phead)
- {
- if (phead == NULL)
- {
- printf("NULL");//如果链表没有元素就打印NULL
- return;
- }
- SListNode* cur = phead;
- //循环单链表打印
- while (cur != NULL)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
-
- //3. 头插
- void SListPushFront(SListNode** phead, SListDataType x)
- {
- assert(phead);
- SListNode* newnode =SListCreatNode(x);//创建一个新节点
- newnode->next =*phead;
- *phead = newnode;
- }
-
- //4. 头删
- void SListPopFront(SListNode** phead)
- {
- assert(phead);
- assert(*phead);//如果没有数据就不用头删,并报错
- SListNode* cur = (*phead)->next;
- free(*phead);
- *phead = cur;
- }
-
- //5. 尾插
- void SListPushBack(SListNode** phead, SListDataType x)
- {
- assert(phead);
- if (*phead == NULL)
- {
- *phead = SListCreatNode(x);//创建新节点并插入
- }
- else
- {
- SListNode* tail = *phead;
- while (tail->next != NULL)//找到尾节点
- {
- tail = tail->next;
- }
- tail->next = SListCreatNode(x);//创建新节点并插入
- }
- }
-
- //6. 尾删
- void SListPopBack(SListNode** phead)
- {
- assert(phead);
- assert(*phead);//链表为空就不进行尾删
- SListNode* tail = *phead;
- if (tail->next == NULL)//如果链表就只有一个元素就进行头删
- {
- SListPopFront(phead);
- }
- else
- {
- while (tail->next->next != NULL)
- {
- tail = tail->next;
- }
- free(tail->next);
- tail->next = NULL;
- }
- }
-
- //7. 查找元素X
- SListNode* SListFind(SListNode* phead, SListDataType x)
- {
- assert(phead);
- while (phead->next!=NULL)//注意最后一个节点是没有查找的
- {
- if (phead->data == x)
- return phead;
- phead = phead->next;
- }
- if (phead->data == x)
- return phead;//最后一个节点没有查找
- else
- return NULL;//没找到
- }
-
- //8. 在pos位置修改
- void SListModify( SListNode* pos, SListDataType x)
- {
- assert(pos);
- pos->data = x;
- }
-
- //9. 在任意位置之前插入
- void SListInsert(SListNode** phead, SListNode* pos, SListDataType x)
- {
- assert(phead);
- assert(*phead);
- if (pos==*phead)//如果pos位置刚好是第一个节点就进行头插
- {
- SListPushFront( phead,x);
- }
- else
- {
- SListNode* newnode = SListCreatNode(x);
- SListNode* cur = *phead;
- while (cur->next != pos)//找到pos前一个节点
- {
- cur = cur->next;
- }
- cur->next = newnode;
- newnode->next = pos;
- }
- }
-
- //10. 在任意位置删除
- void SListErase(SListNode** phead, SListNode* pos)
- {
- assert(phead && *phead && pos);
- if (pos==*phead)//如果pos位置就是第一个节点就进行头删
- {
- SListPopFront(phead);
- }
- else
- {
- SListNode* cur = *phead;
- while (cur->next != pos)//找到pos前一个节点
- {
- cur = cur->next;
- }
- cur->next = pos->next;
- free(pos);
- }
- }
-
- //11. 销毁单链表
- void SListDestroy(SListNode** phead)
- {
- assert(*phead && phead);
- SListNode* cur = *phead;
- while (cur!= NULL)
- {
- SListNode* tmp = cur->next;
- free(cur);
- cur = tmp;
- }
- *phead = NULL;
- }

好了,这期的分享到这里就结束了~
如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~
如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~
我们下期不见不散~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。