关于在指定位置的插入删除操作
但因为单链表的特性:无法倒着遍历,所以在pos之前的插入要麻烦的多,并且无法用其去简化其他函数。
以下是在pos之前插入:
//在pos位置之前插入x -- 单链表不太适合在之前插入 -- 比较复杂 -- 尾插函数中也无法复用
void SListInsertBefore(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
assert(pphead);
assert(pos);
SLTNode* newNode = BuyListNode(x);
if (pos == *pphead)
{
newNode->next = *pphead;
*pphead = newNode;
}
else
{
// 找到pos的前一个位置
SLTNode* posPrev = *pphead;
while (posPrev->next != pos)
{
posPrev = posPrev->next;
}
posPrev->next = newNode;
newNode->next = pos;
}
}
因为插入操作会改变头链表,所以要传入二级指针。
先将新数据x建立一个新节点newNode来存放,用自己编写的函数 BuyListNode,
然后判断pos位置是不是头指针的位置,
如果是,就将newNode->next去指向原头节点,让newNode成为新的头结点;
如果不是,就需要定义一个工作指针posPrev来存放上一个节点的位置,来解决找pos上一个位置的问题,遍历链表,在找到pos位置后,posPrev便是pos上一个节点的位置,再将新的节点插入到pos的前一个位置上。
删除在pos位置的值:
//删除在pos位置的值
void SListErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
if (*pphead == pos)
{
//*pphead = pos->next;
//free(pos);
SListPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
需要判断pos位置是否是头结点 ,如果是,直接调用头删,
如果不是,还是需要定义一个prev来存储前一个节点的位置,在遍历链表找到pos位置后,将pos前一个位置的节点prev和pos下一个节点pos->next连上,然后释放pos位置的节点,并将pos位置置空。
--------------------------------------------------------------------------------------------------------------------------------
因为在pos位置之前插入和在pos位置删除都需要定义一个prev来保证能找到前一个节点,代码因此比较复杂,所以通常关于pos位置的插入删除我们都是指在pos位置之后插入,在pos位置之后删除,代码要相对简单的多,且可以在头插、头删、尾插、尾删之中调用。
在pos位置之后插入:
//在pos位置之后插入x -- 这个更适合单链表
void SListInsertAfter(SLTNode* pos, SLTDateType x)
{
assert(pos);
SLTNode* newNode = BuyListNode(x);
newNode->next = pos->next;
pos->next = newNode;
}
这个就只需要在新建一个节点后直接进行插入就行,不需要再找前一个节点了(这样操作与其前一个节点无关)。
删除在pos之后的值:
//删除pos位置之后的值
void SListEraseAfter(SLTNode* pos)
{
assert(pos);
assert(pos->next);
SLTNode* next = pos->next;
pos->next = next->next;
free(next);
next = NULL;
}
这个也一样不需要再考虑前一个节点的事情,只需要关注pos位置的节点和pos下一个位置的节点。