文章目录
前言
- 一、单链表是什么?
- 二、单链表的实现
- 总结
顺序表的缺点
1.中间/头部的插入删除,时间复杂度为O (N)
2.realloc 扩容(特别是异地扩,需要申请新空间,拷贝数据,释放旧空间)会有不小的消耗。
3.增容一般是呈2倍的增长,势必会有一定的空间浪费。 例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
针对顺序表的缺点,设计了链表
一、单链表是什么?
链表是数据结构之一,其中的数据呈线性排列。在链表中,数据的添加和删除都较为方便,就是访问比较耗费时间。
1.2结构
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SLTNode;
这就是单链表的经典结构
其实一个链表还分逻辑模型和物理模型
逻辑模型
物理模型
二.单链表的实现(接口函数的实现)
2.1打印
打印只有一个细节就是cur = cur->next,cur是一个结构体指针,可以通过->去访问成员,他的意思就是往下去遍历。
void SListPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
}
2.2检查扩容
和之前的顺序表的思路是一样的,单链表也是需要检查扩容的,如果满了就要扩,如果少了就要增。
SLTNode* BuyListNode(SLTDateType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
newnode->data = x;
newnode->next = NULL;
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
return newnode;
}
2.3尾插
利用两个指针,先检查扩容,如果是空的就增容,然后先找到尾,然后在把新开辟的内存链接起来就可以了。
void SListPushBack(SLTNode** pphead, SLTDateType x)
{
SLTNode* newnode = BuyListNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
//找到尾节点
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
2.4头插
注意要不要传2级指针,只有判断是否使用phead
void SListPushFront(SLTNode** pphead, SLTDateType x)
{
SLTNode* newnode = BuyListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
2.5尾删
尾删有两个方法,两个指针和单指针
两个指针法
将最后一组元素释放,在将最后一个元素置空,但是一个节点要单独考虑
void SListPopBack(SLTNode** pphead)
{
assert(*pphead != NULL);
if ((*pphead)->next = NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* prev = NULL;
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
prev->next = NULL;
}
}
单指针法
void SListPopBack(SLTNode** pphead)
{
SLTNode*tail=*pphead;
assert(*pphead != NULL);
if ((*pphead)->next = NULL)
{
free(*pphead);
*pphead = NULL;
}
while(tail->next->next!=NULL)
{
tail=tail->next;
}
free(tail->next);
tail->next=NULL;
}
2.6头删
保存下一节点next,删除头节,点将头节点赋值为next。
void SListPopFront(SLTNode** pphead)
{
assert(*pphead != NULL);
SLTNode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
2.7查找
SLTNode* SListFind(SLTNode* phead, SLTDateType x)
{
SLTNode* cur = phead;
while (cur != NULL)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
2.8在pos位置之前去插入一个节点
先要找到他的位置,找到pos之前的位置
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
SLTNode* newnode = BuyListNode(x);
if (*pphead == pos)
{
newnode->next = *pphead;
*pphead = newnode;
}
else//找到pos之前的位置
{
SLTNode* posprev = *pphead;
while (posprev->next != pos)
{
posprev = posprev->next;
}
posprev->next = newnode;
newnode->next = pos;
}
}
2.8在pos位置之后去插入一个节点
void SListInsertAfter(SListNode* pos, SListData x)
{
assert(pos);
SListNode* newnode = BuyListNode(x);
SListNode* next = pos->next;
pos->next = newnode;
pos->next->next = next;
}
2.9在pos位置去删去一个结点(头要特殊处理)
void SListInsert(SListNode** pphead, SListNode* pos, SListData x)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
*pphead=pos->next;
free(pos);
}
else
{
SListNode* pre = *pphead;//找到前一个
while (pre->next != pos)
{
pre = pre->next;
}
pre->next = pos->next;//前一个指向后一个
free(pos);
}
}
3.0销毁,还原
void SListDestory(SLTNode**pphead)
{
SLTNode*cur=*pphead;
while(cur!=NULL)
{
SLTNode*next=cur->next;
free(cur);
cur=next;
}
*pphead=NULL;
}
总结
单链表的缺点就是不可以随机访问,而顺序表却可以做到,说明单链表也有缺陷,那什么结构可以让我们更好?只有继续的学习才会知道。