目录
顺序表的问题:
1、尾部插入可以,但是头插或者中间的插入,需要挪动中间的数据,效率底下
2、扩容需要付出代价,例如内存空间的碎片化、以及对空间的利用不充分。比如说只有101个数据,空间满足是100,只能扩容到200,便浪费了大量的空间。扩容的少,便会频繁扩容;扩容的多,导致浪费。
那么为了解决这个问题,就有人提出,能不能我要多少内存我就申请多少内存呢?例如说,我要三个,就给三个,要5个就给5个。但是这些空间并不是连续的。这个时候问题又来了,我要如何管理这些数据的空间呢?原来的数组存储空间是来连续的,但是现在空间是不连续的,也就是说地址是不连续的,也就意味着不能使用下标的方式来解决。怎么办呢?用指针来处理。而这些一个一个的内存空间一般喜欢叫做节点。那么我们怎么找到这些数据呢?一般来说,我们将第一个节点的位置叫做phead,让上一个位置存下一个数据的地址,以此类推,便串起来了
每个节点之间没有关联,是随机分配的。物理上不是线性的,只是逻辑上是我们想象的连续。
每个节点有两个数据,一个存储数据,一个是存储下一个节点的地址
exit(-1)表示异常终止
exit(0)表示正常终止
内部改变外部,一定要解引用,不一定传了指针就会改变
第一个plist是一级指针,要改变就需要传2级指针,2级指针就是一级指针的地址,改变一级指针的地址才能改变一级指针。
改变int,传int*;改变int* ,传int**
改变结构体只需要->操作符即可,->本质上也是一种解引用
只要不是改变当前栈帧的变量,都要通过一个中间量(指针)来修改
尾删:
1、双指针
2、tail->next->next
free本质是释放空间,而不是指向这个空间的指针
尾删除:表为空、表只有一个节点、表有多个节点
在pos之前插入,STL使用的是*SLNode pos,指针位移量
连续定义指针,需要在变量之前加一个*,这是基础语法
带哨兵位的链表:第一个节点不存储有效数据
?
对于单链表来说,只能从前找到后,不能从后找到前面,所以再pos位置后插入比较合适
同理,对于删除pos位置也是一样,删除pos前的位置还需要再找前节点,相对比较麻烦,尽管课可以实现,但是在有更优解的情况下,自然选择简单易行的。
在任意位置插入(pos位置之后):
找到pos位置,记录pos位置的下一个位置,链接
如果pos是最后一个位置,需要特殊处理,但是如果pos不是最后一个节点,就不需要特殊处理,正常处理
如果是插入到pos前一个位置,就需要特别处理,分情况
但是注意:
1、链表为空的时候
2、链表只有一个节点的时候
3、检查pos的位置是否合法
删除任意位置(pos后):
1、pos是头节点,头删
2、pos是最后一个位置,尾删
3、pos是中间节点,正常处理
在任意位置插入(pos前):
1、检查pos节点
2、检查链表
3、只有一个节点,直接删除
4、最后一个节点,和正常删除一样
5、删头,特殊处理
销毁链表:
1、保存下一个节点,删除当前节点
2、最后链表指针置空
//头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
// slist.h
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode** pplist,SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode** pplist,SListNode* pos);
// 在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x);
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos);
void SLTDestroy(SListNode** pplist);
//实现文件
#pragma once
#include"SList.h"
SListNode* BuySListNode(SLTDateType x)
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp == NULL)
{
perror("malloc fail \n");
exit(-1);
}
SListNode* newnode = tmp;
newnode->data = x;
newnode->next = NULL;
}
// 单链表打印
void SListPrint(SListNode* plist)
{
assert(plist);
SListNode* cur = plist;
/*while (cur->next != NULL)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");*/
do
{
printf("%d ", cur->data);
cur = cur->next;
} while (cur != NULL);
printf("\n");
}
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
//判断
assert(pplist);
if ((*pplist) == NULL)
{
(*pplist) = BuySListNode(x);
}
else
{
SListNode* cur = *pplist;
while (cur->next != NULL)
{
cur = cur->next;
}
SListNode* newnode = BuySListNode(x);
cur->next = newnode;
}
}
//单链表头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
assert(pplist);
//判链表为空
if ((*pplist) == NULL)
{
*pplist = BuySListNode(x);
}
else
{
SListNode* phead = *pplist;
SListNode* newnode = BuySListNode(x);
newnode->next = phead;
*pplist = newnode;
}
}
// 单链表的尾删
void SListPopBack(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
//只有一个节点
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
//前后指针,保留前一个节点位置,释放最后一个位置
SListNode* cur = *pplist;
SListNode* prev = *pplist;
while (cur->next != NULL)
{
prev = cur;
cur = cur->next;
}
free(cur);
cur = NULL;
prev->next = NULL;
}
}
// 单链表头删
void SListPopFront(SListNode** pplist)
{
assert(pplist);
//空表
assert(*pplist);
//只有一个节点
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* first = (*pplist)->next;
free(*pplist);
*pplist = first;
}
}
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
//检查空
assert(plist);
SListNode* cur = plist;
while (cur != NULL)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode** pplist, SListNode* pos, SLTDateType x)
{
assert(pplist);
assert(*pplist);
assert(pos);
SListNode* cur = *pplist;
SListNode* next = cur->next;
while (cur != pos)
{
cur = cur->next;
next = cur->next;
}
if (next == NULL)//尾插
{
SListPushBack(pplist,x);
}
else
{
SListNode * newnode = BuySListNode(x);
newnode->next = next;
cur->next = newnode;
}
}
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode** pplist, SListNode* pos)
{
assert(pplist);
assert(*pplist);
assert(pos);
//头删
if (pos == *pplist)
{
SListPopFront(pplist);
return;
}
//尾删
if (pos->next == NULL)
{
SListPopBack(pplist);
return;
}
SListNode* cur = *pplist;
SListNode* prev = cur;
SListNode* next = cur->next;
while (cur != pos)
{
prev = cur;
cur = cur->next;
next = cur->next;
}
prev->next = next;
free(pos);
pos = NULL;
}
// 在pos插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x)
{
assert(pplist);
assert(*pplist);
assert(pos);
if(pos == *pplist)
{
SListPushFront(pplist,x);
}
else
{
SListNode* prev = *pplist;
SListNode* cur = *pplist;
while(cur != pos)
{
prev = cur;
cur = cur->next;
}
SListNode* newnode = BuySListNode(x);
prev->next = newnode;
newnode->next = pos;
}
}
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos)
{
assert(pplist);
assert(*pplist);
assert(pos);
if (pos == *pplist)
{
SListPopFront(pplist);
return;
}
else
{
SListNode* prev = *pplist;
SListNode* cur = *pplist;
SListNode* next = cur->next;
while (cur != pos)
{
prev = cur;
cur = cur->next;
next = cur->next;
}
if (cur->next == NULL)
{
SListPopBack(pplist);
return;
}
else
{
prev->next = next;
free(pos);
pos = NULL;
}
}
}
void SLTDestroy(SListNode** pplist)
{
assert(pplist);
SListNode* cur = *pplist;
while (cur)
{
SListNode* next = cur->next;
free(cur);
cur = next;
}
*pplist = NULL;
printf("SLTDestroy success!\n");
}
//测试文件
#include"SList.h"
SListNode* plist;
//尾插测试
void test1()
{
SListPushBack(&plist,1);
SListPushBack(&plist,2);
SListPushBack(&plist,3);
SListPushBack(&plist,4);
SListPushBack(&plist,5);
SListPrint(plist);
SLTDestroy(&plist);
}
//头插测试
void test2()
{
SListPushFront(&plist,1);
SListPushFront(&plist,2);
SListPushFront(&plist,3);
SListPushFront(&plist,4);
SListPushFront(&plist,5);
SListPrint(plist);
SLTDestroy(&plist);
}
//尾删测试
void test3()
{
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPushFront(&plist, 5);
SListPopBack(&plist);
SListPopBack(&plist);
SListPopBack(&plist);
SListPopBack(&plist);
SListPopBack(&plist);//打印出问题
SListPopBack(&plist);//再删出问题
SListPrint(plist);
SLTDestroy(&plist);
}
//头删测试
void test4()
{
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPushFront(&plist, 5);
SListPopFront(&plist);
SListPopFront(&plist);
SListPopFront(&plist);
SListPopFront(&plist);
SListPrint(plist);
SLTDestroy(&plist);
}
//查
void test5()
{
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPushFront(&plist, 5);
SListFind(plist,1);
SListFind(plist,6);
SLTDestroy(&plist);
}
//pos后插入
void test6()
{
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPushFront(&plist, 5);
SListInsertAfter(&plist, SListFind(plist,1),6);
SListInsertAfter(&plist, SListFind(plist,1),7);
SListInsertAfter(&plist,SListFind(plist,5),10);
SListInsertAfter(&plist,SListFind(plist,5),11);
SLTDestroy(&plist);
SListPrint(plist);
}
//pos后插入
void test7()
{
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPushFront(&plist, 5);
SListEraseAfter(&plist,SListFind(plist,5));
SListEraseAfter(&plist,SListFind(plist,1));
SListEraseAfter(&plist,SListFind(plist,3));
SListPrint(plist);
SLTDestroy(&plist);
}
//插pos位置
void test8()
{
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPushFront(&plist, 5);
SLTInsert(&plist,SListFind(plist,1), -1);
SLTInsert(&plist,SListFind(plist,5), 6);
SLTInsert(&plist,SListFind(plist,3), 100);
SListPrint(plist);
SLTDestroy(&plist);
}
//删pos位置
void test9()
{
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPushFront(&plist, 5);
SLTErase(&plist, SListFind(plist,1));
SLTErase(&plist, SListFind(plist,5));
SLTErase(&plist, SListFind(plist,3));
SListPrint(plist);
SLTDestroy(&plist);
}
int main()
{
//test1();
//test2();
//test3();
//test4();
//test5();
//test6();
//test7();
//test8();
test9();
return 0;
}