三、函数定义
查找节点
//查找结点
SLTNode* SLTNodeFind(SLTNode* phead, SLTDataType x)
{assert(phead);SLTNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}
查找节点我们是通过看数据域来查找的,查找节点函数的返回值类型是SLTNode* 因为不涉及到链表的修改,我们只需要传值;同样地,首=首先要断言看链表是否为空;为了方便遍历链表,我们定义一个节点pcur,在循环中没经历一个节点时,就拿这个节点地数据域的值和传入的数据进行比较,直到最后一个几点,如果某个节点的数据域的值和传入的值相同,就返回这个节点,若是遍历完链表还是找不到,说明这个链表没有要查找的节点,那么就返回NULL。
相关测试:
指定位置之前插入数据
//在指定位置之前插入数据
void SLTInsertFront(SLTNode** pphead,SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);if (pos == *pphead){SLTPushFront(pphead, x);}else{SLTNode* newnode = SLTBuyNode(x);SLTNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}pre->next = newnode;newnode->next = pos;}
}
需要配合SLNodeFind一起使用。链表不能为空,指定的位置处的节点也不能为空;先看到else中的内容,若是指定的位置不是头节点,为传入的数据申请一个新节点,循环找到pos前的节点,让pre的next指针指向newnode,newnode的next指针指向pos,这样就让链表多了一个指定位置之前的节点;若是pos就是头节点此时不能直接走else里面的内容,因为pre找不到,最终会是空,此时直接引用头插方法。
相关测试:
指定位置之后插入数据
//在指定位置之后插入数据
void SLTInsertBack(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);SLTNode* next = pos->next;pos->next = newnode;newnode->next = next;
}
不需要传头节点,因为不需要找到指定位置之前的节点,只需要pos和pos之后的节点,先把pos之后的节点给存起来,再让pos的next指向newnode,再让newnode的next指向原链表pos之后的节点。
删除指定位置的节点
//删除指定位置的数据
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);SLTNode* pre = *pphead;SLTNode* next = pos->next;if (pos == *pphead){SLTPopFront(pphead);}else{while (pre->next != pos){pre = pre->next;}free(pos);pos = NULL;pre->next = next;}
}
同样地,如果pos就等于*pphead那么直接循环则找不到pre,这个时候直接调用头删的函数;若是正常情况下,则先找到pos之前的节点,再释放pos处的节点,最后让pre的next指向next的节点(也就是原链表中pro的next节点)。
删除指定位置之后的节点
//删除指定位置之后的数据
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}
我们需要找到pos下一个和pos下下个的节点,因为删除了pos之后的节点之后要让pos的next指向pos的下下个节点;若是直接先 (pos->next=pos->next->next)再(free(pos->next)),这样会错误地删除原本链表中pos的下下个节点;
为了避免这种错误,我们先定义一个del节点存放要删除的节点,再让pos的next指向pos的下下个节点,最后删除del节点,因为此时的del的定义是在改变pos地next之前进行的,所以del代表的就是原链表pos的下一个节点并且不会改变,我们此时直接删除del不会对新链表造成破坏,这样就实现了该函数功能。
销毁单链表
//销毁单链表
void SLTDestroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;//SLTNode* next = NULL;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}
销毁单链表需要对其节点一个一个释放;我们对下面这个链表进行销毁并且调试观察;
在链表尾插完之后在内存中是这样的:
在进行销毁的前一刻内存中是这样的:
销毁了三次之后:
销毁完节点并且让*pphead置为空之后:
如此就完成了单链表的销毁。