顺序表问题及思考
问题:
- 中间/头部的插入删除,时间复杂度为O(N)
- 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
- 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,
我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
链表的概念及结构
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
链表是单独存储数据通过指针指向下一个地址。
链表的分类
带哨兵位的头节点不存数据。
总共有八种结构,但我们最常用的有无头单项非循环链表和有头双项循环链表
打印链表节点数据
void SListPrint(SLTNode* plist)
{
SLTNode* cur = plist;
while (cur != NULL)
{
printf("%d "cur->data);
cur = cur->next;
}
printf("\n");
}
建立一个新的节点
SLTNode *BuySLTNode(SLTDataType x)
{
SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
node->data = x;
node->next = NULL;
}
先用Malloc动态开辟空间,然后创建新的节点
尾插
void SListPushBack(SLTNode** plist, SLTDataType x)
{
if (plist == NULL)
{
plist = newnode;
}
else
{
SLTNode* tail = plist;
while (tail->next != NULL)
{
tail = tail->next;
}
SListNode *newnode = BuySLTNode(x);
tail->next = newnode;
}
}
由于我们是对指针进行改变,所以用来接收的是二级指针。
要记得判断刚开始就是空指针的情况。
头插
void SListPushFront(SLTNode** pplist, SLTDataType x)
{
SLTNode* newnode = BuySLTNode(x);
newnode->next = *pplist;
*pplist = newnode;
}
由于对一级指针进行改变,所以用来接收的是二级指针。
尾删
void SListPopBack(SLTNode* plist)
{
if (*pplist == NULL)
{
return;
}
else if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SLTNode* prev = NULL;
SLTNode* tail = plist;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
prev->next = NULL;
}
}
要分情况,没有节点,一个节点和多个节点的情况。
头删
void SListPopFront(SLTNode ** pplist)
{
if (*pplist == NULL)
{
return;
}
else
{
SLTNode* next = (*pplist)->next;
free(*pplist);
*pplist = next;
}
}
头删要记得先保存下一个,再把开头的free掉。
查找
void SLTNode* SListFinde(SLTNode* plist, SLTDataType x)
{
SLTNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
}
任意位置前插入
void SListInsert(SLTNode* plist, SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuySLTNode(x);
if (pos == *pplist)
{
newnode->next = pos;
*pplist = newnode;
}
SLTNode* prev = NULL;
SLTNode* cur = plist;
while (cur != pos)
{
prev = cur;
cur = cur->next;
}
prev->next = newnode;
newnode->next = pos;
}
要注意考虑头节点的情况。
任意位置后插入
void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuySLTNode(x);
pos->next = newnode;
newnode->next = pos->next;
}