-
顺序表存在的问题:
- 中间/头部的插入删除,时间复杂度为O(N)
- 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗
- 增容一般是呈2倍的增长,势必会有一定的空间浪费。
例如当前容量为100,满了以后增容到200,如果再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。所以这时就引入了链表的概念,来解决这一系列问题。
-
链表的概念及结构
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
- 单向、 双向
- 带头、不带头
- 循环、非循环
虽然说有8种数据结构,但是我们最常用的是以下两种结构:
- 无头单向非循环链表:
结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
- 带头双向循环链表:
结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现就可以知道。
-
单链表各个接口的实现:
-
<Slist.h>
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType _data;
struct SListNode* _next;
}SListNode;
typedef struct SList
{
SListNode* _head;
SListNode* _tail;
}SList;
void SListInit(SList* plist);
void SListDestroy(SList* plist);
void SListPushBack(SList* plist, SLTDataType x);
void SListPopBack(SList* plist);
void SListPushFront(SList* plist, SLTDataType x);
void SListPopFront(SList* plist);
SListNode* SListFind(SList* plist, SLTDataType x);
void SListInsertAfter(SList* plist, SListNode* pos, SLTDataType x);//在pos后面插入
void SListEraseAfter(SListNode* pos);
void SListRemove(SList* plist, SLTDataType x);
void SListPrint(SList* plist);
-
<Slist.c>
#include "SList.h"
void SListInit(SList* plist)
{
assert(plist);
plist->_head = NULL;
plist->_tail = NULL;
}
void SListDestroy(SList* plist)
{
SListNode* cur;
assert(plist);
cur = plist->_head;
while (cur)
{
SListNode* next = cur->_next;
free(cur);
cur = next;
}
plist->_head = plist->_tail = NULL;
}
SListNode* BuySListNode(SLTDataType x)
{
SListNode* node = (SListNode*)malloc(sizeof(SListNode));
assert(node);
node->_data = x;
node->_next = NULL;
return node;
}
void SListPushBack(SList* plist, SLTDataType x)
{
SListNode* tail;
assert(plist);
//1.一个节点没有
//2.一个以上节点
/*if (plist->_tail == NULL)
{
plist->_head = plist->_tail = BuySListNode(x);
}
else
{
SListNode* newnode = BuySListNode(x);
plist->_tail->_next = newnode;
plist->_tail = newnode;
}*/
if (plist->_head == NULL)
{
plist->_head = BuySListNode(x);
}
else
{
tail = plist->_head;
while (tail->_next)
{
tail = tail->_next;
}
tail->_next = BuySListNode(x);
}
}
void SListPopBack(SList* plist)
{
assert(plist);
SListNode* prev, *tail;
prev = NULL;
tail = plist->_head;
if (tail->_next == NULL)
{
free(tail);
plist->_head = NULL;
}
else
{
while (tail->_next)
{
prev = tail;
tail = tail->_next;
}
free(tail);
prev->_next = NULL;
}
}
void SListPushFront(SList* plist, SLTDataType x)
{
SListNode* newnode;
assert(plist);
newnode = BuySListNode(x);
newnode->_next = plist->_head;
plist->_head = newnode;
}
void SListPopFront(SList* plist)
{
SListNode* next;
assert(plist);
next = plist->_head->_next;
free(plist->_head);
plist->_head = next;
}
SListNode* SListFind(SList* plist, SLTDataType x)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur)
{
if (cur->_data== x)
{
return cur;
}
else
{
cur = cur->_next;
}
}
return cur;
}
void SListInsertAfter(SList* plist,SListNode* pos, SLTDataType x)//在pos后面插入
{
assert(pos);
SListNode* next ,*newnode;
next = pos->_next;
newnode = BuySListNode(x);
newnode->_next = next;
pos->_next = newnode;
}
void SListEraseAfter(SListNode* pos)//删除pos后面的节点
{
assert(pos);
SListNode* next;
if (pos->_next == NULL)
{
return;
}
next = pos->_next->_next;
free(pos->_next);
pos->_next = next;
}
void SListRemove(SList* plist, SLTDataType x)//删除某个给定的数
{
assert(plist);
if (plist->_head->_data == x)
{
SListPopFront(plist);
return;
}
SListNode* prev = NULL;
SListNode* cur = plist->_head;
while (cur)
{
if (cur->_data == x)
{
prev->_next = cur->_next;
free(cur);
cur = NULL;
break;
}
else
{
prev = cur;
cur = cur->_next;
}
}
}
void SListPrint(SList* plist)
{
assert(plist);
SListNode* cur = plist->_head;
while (cur)
{
printf("%d-> ", cur->_data);
cur = cur->_next;
}
printf("NULL\n");
}
-
<test.c>
#include "SList.h"
void TestSList()
{
SList sl;
SListInit(&sl);
SListPushBack(&sl, 1);
SListPushBack(&sl, 2);
SListPushBack(&sl, 3);
SListPushBack(&sl, 4);
SListPushBack(&sl, 5);
SListPopBack(&sl);
SListPushFront(&sl, 0);
SListPopFront(&sl);
SListNode* pos = SListFind(&sl, 3);
SListInsertAfter(&sl,pos, 6);
SListEraseAfter(pos);
SListRemove(&sl, 3);
SListPrint(&sl);
}
int main()
{
TestSList();
system("pause");
return 0;
}