链表
链表结构
顺序表是连续的类似数组,链表可以不连续,物理上不是线性的
当只是尾插尾删只用顺序表也可以,但是需要到头插头删的时候,还是需要链表,因为链表没有增容的代价,链表是需要一个就开辟一个
phead和plist的关系
pphead、*pphead、plist的关系
打印函数
void SListPrint(SLTNode* phead)
{
SLTNode *cur = phead;//新建一个节点指向phead,phead为plist的地址,要用指针指向地址
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");//最后一个结点指向NULL,输出在结尾
}
尾插和前插函数
- 需要借助BuySListNode来开辟新的结点
SLTNode* BuySListNode(SLTDataType x)
{//新建(开辟)新的结点
SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
if(node == NULL)
{
printf("malloc fail\n");
exit(-1);//内存申请不出来,就通过exit来以-1的标志退出
}
node->data = x;
node->next = NULL;
return node;
}
//尾插
void SListPushBack(SLTNode **pphead, SLTDataType x)
{
//结点为空的时候 - 新创建的结点直接插入当作尾结点
if (*pphead == NULL)
{
SLTNode *newnode = BuySListNode(x);
*pphead = newnode;
}
//结点不为空的时候
else
{
//用tail(结构体)指针来指向头节点一直往下找直到找到尾结点
SLTNode* tail = *pphead;//tail(结构体)指针来指向头节点
while (tail->next != NULL)
{
tail = tail->next;
}
SLTNode *newnode = BuySListNode(x);//找到尾结点后直接插入新的结点当作新的尾结点
tail->next = newnode;//连接(插入)新的尾结点
}
}
//前插
void SListPushFront(SLTNode **pphead, SLTDataType x)
{
SLTNode *newnode = BuySListNode(x);
newnode->next = *pphead;//把第一个节点的地址(plist(*pphead)指向第一个节点的地址)传给新节点中
*pphead = newnode;//把新节点的地址传给pliat
}
尾插
尾插失败的原因:不能使用指针传值
解决指针传值的问题:传二级指针(函数里面需要改变phead的时候就需要传二级指针,不需要的时候就传一级指针)
头插
理解方法1:
理解方法2:
尾删和头删函数
//尾删- -两种方法
void SListPopBack(SLTNode **pphead)
{
assert(pphead);//判断参数是否传错
//没有结点断言报错- -处理暴躁
assert(*pphead);//链表为空的时候还在调用尾删会报错
//温和处理
//if (*pphead == NULL)
//{
// return;
//}
//一个结点
if ((*pphead)->next == NULL)//plist->next就是d1的next
{
free(*pphead);
*pphead = NULL;
}
//多个结点
else
{
//方法1
SLTNode *prev = NULL;
SLTNode *tail = *pphead;//pphead解引用找到plist
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
prev->next = NULL;
//方法2
//SLTNode *tail = *pphead;
//while (tail->next->next != NULL)
//{
// tail = tail->next;
//}
//free(tail->next);
//tail->next = NULL;
}
}
//头删
void SListPopFront(SLTNode** pphead)
{
assert(pphead);//plist一定有地址,所以pphead不为空
//链表为空
assert(*pphead);
//只有一个结点
//if ((*pphead)->next == NULL)//(*pphead)->next就是第一个结点的next
//{
// free(*pphead);
// *pphead = NULL;
//}
多个结点
//else
//{
// SLTNode* next = (*pphead)->next;//plist->next就是d1的next即d2
// free(*pphead);//free掉的是d1
// (*pphead) = next;//plist指向d2
//}
//可以同时处理一个和多个结点
SLTNode* next = (*pphead)->next;
free(*pphead);
(*pphead) = next;
}
尾删
test.c中一直尾删(链表可能会为空)会出错,所以得考虑代码节点的多种情况
头删
size、Empty函数
//链表的空间
int SListSize(SLTNode* phead)
{
int size = 0;
SLTNode* cur = phead;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
bool SListEmpty(SLTNode* phead)//bool只有0和1两种情况
{
//方法1
//return phead == NULL;
//方法2
/*if (phead == NULL)
{
return true;
}
else
{
return false;
}*/
//方法3
return phead == NULL ? true : false;
}
test.c
销毁
//销毁
void SListDestory(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;//销毁完所有的节点以后plist要指向空而不是原来的节点
}
查找 - 修改函数
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
text.c
任意位置的插入函数
单链表更适合在pos位置之后的插入,在pos之前很麻烦还得找到pos
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
// 1、头插
// 2、后面插入
if (*pphead == pos)
{
SListPushFront(pphead, x);
}
else
{
// 找到pos位置的前一个节点
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SLTNode* newnode = BuySListNode(x);
newnode->next = pos;
prev->next = newnode;
}
}
// 在pos位置后面去插入x
void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);//防止pos输入不规范
SLTNode* newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
删除函数
删除pos
// 删除pos位置的值
void SListErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
// 1、头删
// 2、后面节点删除
if (pos == *pphead)
{
SListPopFront(pphead);
}
else
{
// 找到pos位置的前一个节点
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
删除pos后一个位置
//删除
void SListEraseAfter(SLTNode* pos)
{
assert(pos);
assert(pos->next);//pos的下一个位置不能为空,防止next为空下面会出错
SLTNode* next = pos->next;
pos->next = next->next;
free(next);
next = NULL;
}