文章目录
前言
- 一、单链表是什么?
- 二、单链表的实现
- 总结
顺序表的缺点
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;
}
总结
单链表的缺点就是不可以随机访问,而顺序表却可以做到,说明单链表也有缺陷,那什么结构可以让我们更好?只有继续的学习才会知道。