通过前面几次的博文,我们已经对线性结构的定义和一些基本运算,比如初始化、判空、插入,有了基本的了解,对于代码的熟悉程度也大大提高。本篇博文,小编将和大家一起学习继续学习线性结构运算——删除。
链式存储
(一)单链表
void DeleteLinklist(Linklist head,int i)
//链式存储——删除结点,删除表head的第i个结点
{
Node *q;
if(i==1) q=head;
else q=GetLinklist(head,i-1); //先找待删结点的直接前驱
if(q!=NULL && q->next!=NULL) //若直接前驱存在且待删结点存在
{
p=q->next; //p指向待删结点
q->next=p->next; //移出待删结点
free(p); //释放已移出结点p的空间
}
else exit("找不到要删除的结点"); //结点不存在
}
思路分析:删除单链表的某个结点需要先判断该结点和它的前一个结点是否存在,如果存在,就开始改变指针的指向。如图所示,本操作的指针共涉及三个,步骤共分为两步:(1)描述三个结点之间的链式关系 (2)将第ai-1个结点的指针指向第ai+1个结点,此时ai结点被删除。
(二)出栈
int Pop(LkStk *LS)
//链式存储——出栈,栈顶数据元素通过参数返回,它的直接后继成为新的栈顶
{
LkStk *temp;
if(!EmptyStack(LS)) //判断栈是否为空
{ temp=LS->next; //temp指向栈顶结点
LS->next=temp->next; //原栈顶的下一个结点成为新的栈顶
free(temp); //释放原栈顶结点空间
return 1;
}
else return 0;
}
思路分析:出栈操作始终是栈顶结点出栈,即删除除头结点之后的结点。因此,指针的变化体现在栈顶数据元素结点的变化,每出栈一个结点,指向栈顶数据元素的指针改变一次。
(三)出队
OutQueue(LkQue *LQ)
//链式存储——出队
{
LkQueNode *temp;
if(EmptyQueue(CQ)) //判队列是否为空
{error("队空");return 0;} //队列为空
else{ //队列非空
temp=(LQ->front)->next; //使temp指向队列的首结点
(LQ->front)->next=temp->next; //修改头结点的指针域指向新的首结点
if(temp->next==NULL)
LQ->rear=LQ->front; //无首结点时,front和rear都指向头结点
free(temp);
return 1;
}
}
思路分析:与出栈操作类似,差别在于栈是先进后出,队列是先进先出,因此删除结点后的指针变化有所不同,栈的指针变化表现为指向栈顶数据元素结点的指针,队列的指针变化表现为指向首结点的指针。
异同点
(一)同—整体思路:
1. 判断要删除的结点是否存在
2. 找到待删除的结点
3. 改变指针指向
(二)异
1. 结构不同->图形表示不同->代码表示
2. 线性表:找到待删结点和它的前一个结点,删除完成后,将待删结点的前一个结点指向待删结点的后一个结点;栈:栈顶结点出栈,即栈顶数据元素的指针改变;队列:先入队的结点先出队,即首结点的指针在改变。
顺序存储
(一)线性表
void DeleteSeqList(SeqList L,int i)
//顺序存储,线性表删除结点
{
if(i<1||i>L.length) //检查位置是否合法
exit("非法位置");
for(j=i;j<L.length;j++) //第i个元素的下标为i-1
L.data[j-1]=L.data[j]; //依次左移
L.length--; //表长度减一
}
(二)出栈
int Pop(SeqStk *stk)
//顺序存储——出栈
{
if(EmptyStack(stk)) //判断是否下溢(栈空)
{error("下溢");return 0;}
else{ //未下溢,栈顶元素出栈
stk->top--;
return 1;
}
}
(三)出队
int OutQueue(CycQue CQ)
//顺序存储——出队
{
if(EmptyQueue(CQ)) //判队列是否为空
{error("队列空");return 0;} //队列为空,出队列失败
else{
CQ.front=(CQ.front+1)%maxsize; //不为空,出队列
return 1; //出队列成功
}
}
小结
每一次总结都会发现对相关内容的掌握加深了一些,这就是总结的魅力所在。
原文链接:https://www.f2er.com/datastructure/382256.html