链表的插入:主要包含三种,头插、尾插、固定位置插。
头插:首先创建新的结点,然后修改指针。让新结点的pNext = 头结点,再让头结点->新结点
尾插:先找到最后一个结点,并把它记录下来,再把最后一个结点的pNext域指向新的结点
固定位置插: 给定结点插入,插入到结点前(创建新结点,找到给定结点pPos的前一个结点cur,使得结点cur的pNext = 新结点;新结点的pNext = 该结点的pNext->pNext
主要的代码如下所示:
// 头部插入(先创建新结点,然后修改指针.新结点的pNext = 头结点,再让头结点->新结点)
void SListPushFront(SListNode **ppFirst, DataType data)
{
SListNode *p;//新结点p
SListNode *p1;//用来遍历链表(开始位于头结点处)
p = _CreateNode(data);
p1 = *ppFirst;//空链表的话,直接让新结点做头结点;有一个结点的话,和正常情况相同
p ->pNext = p1;
*ppFirst = p;
}
// 尾部插入(先找到最后一个结点,并把它记录下来,再把最后一个结点的pNext域指向新的结点)
void SListPushBack(SListNode** ppFirst, DataType data)
{
SListNode *p;//新结点p
SListNode *p1;
p = _CreateNode(data);
p1 = *ppFirst;//用来遍历链表(开始位于头结点处)
//空链表
if( (*ppFirst) == NULL ){
*ppFirst = p;
return;
} else{
for(p1 = *ppFirst;p1->pNext != NULL;p1 = p1->pNext)
{
}
p1 ->pNext = p;//此时p1为最后一个结点
}
}
// 给定结点插入,插入到结点前(创建新结点,找到给定结点pPos的前一个结点cur,使得结点cur的pNext = 新结点;
//新结点的pNext = 该结点的pNext->pNext)
void SListInsert(SListNode **ppFirst,SListNode *pPos, DataType data)
{
SListNode *cur;//声明结点p,用来记录头结点
SListNode *p1;
assert(&pPos);
assert(*ppFirst);
cur = *ppFirst;
//在结点前做插入(结点pos肯定在链表中&&pos不是空)
if(pPos == NULL&&(*ppFirst) == NULL)
{//非法
return;
}
//若考虑pPos是第一个结点的情况下,无法找到前一个结点,陷入死循环.此时应该直接头插
else if(pPos == *ppFirst)
{
SListPushFront(&ppFirst,data);
return;//记得return 否则下边加上else
}
//怎么找pos的前一个结点(cur->next==pos就找到了)
else{
while(cur ->pNext != pPos)
{
cur = cur ->pNext;
}
p1 = _CreateNode(data);//创建新结点
p1 ->pNext = pPos;
cur ->pNext = p1;
}
}
链表的删除:主要包含三种,头删、尾删、按结点删、按值删(删第一个、删所有)。
头删:(先free掉第一个结点,再将头结点后移一位)
尾删:先尾部删除(先找到倒数第二个结点,并记录倒数第一个结点,再把倒数第二个结点的pNext域指向NULL;释放掉最后一个结点
按结点删 : 给定结点删除(找到给定结点pPos的前一个结点cur,令cur->pNext = pPos->pNext,再free掉pPos
按值删(删第一个): 按值删除,只删遇到的第一个(查找得到该位置cur,将cur->pNext = cur->pNext->pNext; 再free掉cur)
按值删(删所有):若只有一个结点,和正常情况删除相同。只有一个结点并且第一个结点的值就是要删除的值.将*ppFirst=NULL,再free(*ppFirst);多个结点,循环进行删除。
主要的代码如下所示:
// 头部删除(先free掉第一个结点,再将头结点后移一位)
void SListPopFront(SListNode **ppFirst)
{
SListNode *p;//声明结点p,用来记录头结点
assert(*ppFirst);
p = *ppFirst;//用来遍历链表(开始位于头结点处)
//直接后移头指针.再释放掉头结点,
*ppFirst = (*ppFirst)->pNext;
free(p);
}
// 尾部删除(先找到倒数第二个结点,并记录倒数第一个结点,
//再把倒数第二个结点的pNext域指向NULL;释放掉最后一个结点)
void SListPopBack(SListNode **ppFirst)
{
SListNode *p;//声明结点p
SListNode *p1; //记录最后一个结点
assert(*ppFirst);
p = *ppFirst;//用来遍历链表(开始位于头结点处)
//只有一个结点,直接释放掉该结点,头指针指向NULL.
if(p ->pNext == NULL)
{
free(p);
*ppFirst = NULL;
return;
}
for(p = *ppFirst;p->pNext->pNext != NULL;p = p->pNext)
{
}//此时p为倒数第二个结点
p1 = p->pNext;//p1为最后一个结点
free(p1);
p->pNext = NULL;
}
// 给定结点删除(找到给定结点pPos的前一个结点cur,令cur->pNext = pPos->pNext,再free掉pPos)
void SListErase(SListNode **ppFirst, SListNode *pPos)
{
SListNode *cur;
if(pPos == *ppFirst)
{
SListPopFront(&ppFirst);
return;//记得return 否则下边加上else
}
cur = *ppFirst;
//找pos的前一个结点
while(cur ->pNext != pPos)
{
cur = cur ->pNext;
}
cur ->pNext = pPos->pNext;
free(pPos);
}
// 按值删除,只删遇到的第一个(查找得到该位置cur,将
//cur->pNext = cur->pNext->pNext; 再free掉cur)
void SListRemove(SListNode **ppFirst, DataType data)
{
SListNode *cur ;
SListNode *q ;
SListNode *temp = *ppFirst;
if((*ppFirst)->data == data)
{
*ppFirst =(*ppFirst)->pNext;
free(temp);
return;
}
if((*ppFirst)->pNext->data == data)
{
temp = (*ppFirst)->pNext;
(*ppFirst) ->pNext = temp->pNext;
free(temp);
return;
}
for(cur = *ppFirst; cur ->pNext->data != data; cur = cur->pNext)
{
}
q = cur->pNext;
cur->pNext = q->pNext;
free(q);
return;
}
// 按值删除,删除所有的
//只有一个结点的情况和其他正常情况
void SListRemoveAll(SListNode **ppFirst, DataType data)
{
SListNode *cur;
SListNode *pre;
if(*ppFirst == NULL)
{
printf("链表无元素可删除\n");
return -1;
}
pre = *ppFirst;
cur = *ppFirst;
//只有一个结点并且第一个结点的值就是要删除的值.将*ppFirst=NULL,再free(*ppFirst)
if((*ppFirst)->data==data&&(*ppFirst)->pNext==NULL)
{
*ppFirst=NULL;
free(cur);
return;
}
while(cur != NULL)
{
if(cur ->data == data)
{
pre->pNext = cur ->pNext;
free(cur);
cur=pre->pNext;
continue;//如果找到了,释放cur之后,此时应该cur = pre->pNext,继续循环
}
pre = cur;
cur = cur ->pNext;//没找到的情况,循环后移
}
}
上述代码所包含的创建结点函数如下所示:
//创建新结点,结点的数据域为data,pNext域设置为空
SListNode *_CreateNode(DataType data)
{
SListNode *NewNode; //声明新结点
NewNode = (SListNode *)malloc(sizeof(SListNode));//创建新结点
if(NewNode == NULL)
{
return;
}//创建失败
NewNode ->data = data;
NewNode ->pNext = NULL;//创建成功
}
上述单链表插入与删除的操作中的测试代码如下所示:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
SListNode *result;
SListNode *p1;
SListInit(&p1);
SListPushBack(&p1,1);
SListPushBack(&p1,2);
SListPushBack(&p1,3);
SListPushBack(&p1,2);
SListPushBack(&p1,5);
SListPushBack(&p1,2);
SListPushBack(&p1,6);
SListPushBack(&p1,1);
SListPushBack(&p1,2);
SListPushBack(&p1,3);
SListPushFront(&p1, 0);
SListPushFront(&p1,-1);
result = SListFind(p1,5);
SListInsert(&p1, result, 4);
SListPopBack(&p1);
SListPopFront(&p1);
result = SListFind(p1,3);
SListErase(&p1,result);
SListRemove(&p1, 4);
SListRemoveAll(&p1,2);
SListprint(p1);
SListDestroy(&p1);
SListprint(p1);
system("pause");
return 0;
}