单链表的插入(头插、尾插、固定点插)删除(头删、尾删、按值删一个,按值删所有)

链表的插入:主要包含三种,头插、尾插、固定位置插。

头插:首先创建新的结点,然后修改指针。让新结点的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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值