数据结构第三章:不带头结点的单链表操作

Posted 歌咏^0^

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构第三章:不带头结点的单链表操作相关的知识,希望对你有一定的参考价值。

目录

一、新建一个值为inputData的结点,插到链表中值为frontData的结点的前面

二、在一个有序的链表中,有序(升序)地将值为inputData的结点插入到链表中

三、在已知的链表中删除 值为 delData的结点


一、新建一个值为inputData的结点,插到链表中值为frontData的结点的前面

/*
insert_nodeToList:新建一个值为inputData的结点,插到链表中值为frontData的结点的前面
		如果值为frontData的结点不存在,则插在链表的尾部
		如果值为frontData的结点有多个,则插在第一个的前面
		如果值为frontData的结点是首结点,则使用头插
参数:
		head  链表的首结点	
		inputData 新建结点的数据
		frontData 新结点插在该结点的前面的数据
返回值:
		成功  返回  链表的首结点
		失败  返回   NULL
*/
struct node* insert_nodeToList(struct node *head,ElemType inputData,ElemType frontData)
{
	//1、新建一个结点,并且初始化
	struct node *newNode = new_node(inputData);
	if(newNode==NULL)
	{
		printf("insert_nodeToList error\\n");
		return NULL;
	}
	//遍历链表,找到值为frontData的结点frontNode和它的前面一个结点pre
	struct node *p=head;
	struct node *pre=NULL;
	
	while(p)
	{
		//找到了,此时 p  就是  值为frontData的结点frontNode
		if(p->data == frontData)
			break;
		else{//如果没有找到,则p往链表的下一个结点进行遍历
			pre = p;//记录p结点的上一个结点
			p = p->next;
		}
	}
	
	
	if(p!=NULL)//找到的情况
	{		
		if(p == head)//1、如果值为frontData的结点 是首节点 ,使用头插法,更新首结点
		{
			//新结点的next存储原链表的首结点地址,也就是新结点指向原来的首结点
			newNode->next = head;//newNode->next = p;
			head = newNode;//此时新结点就是链表的首结点
		}
		else{//2、值为frontData的结点在中间
			newNode->next = p;
			pre->next  = newNode;
		}
		
	}
	else{//没找到的情况(如果链表遍历完之后,没找到)  p == NULL ,也就是说值为frontData的结点没有找到,新结点使用尾插
		pre->next = newNode;
	}

	return head;
}

二、在一个有序的链表中,有序(升序)地将值为inputData的结点插入到链表中

/*
insert_nodeToList_sort:在一个有序的链表中,有序(升序)地将值为inputData的结点插入到链表中
	思路:首先找到比inputData值大的第一个结点bigNode,将这个新结点插入到bigNode的前面
				如果找到了
						找到的结点bigNode 是首结点,使用头插
						找到的结点bigNode 是中间结点,使用中间插法
				如果没找到
						说明新结点是最大的,那么使用尾插
参数:
		head  链表的首结点	
		inputData 新建结点的数据
返回值:
		成功  返回  链表的首结点
		失败  返回   NULL
*/
struct node* insert_nodeToList_sort(struct node *head,ElemType inputData)
{
	//1、新建一个结点,并且初始化
	struct node *newNode = new_node(inputData);
	if(newNode==NULL)
	{
		printf("insert_nodeToList error\\n");
		return NULL;
	}
	
	//2、遍历链表,找到比inputData值大的第一个结点bigNode
	struct node *p=head;
	struct node *pre=NULL;
	
	while(p)
	{
		if(p->data > inputData)//此时 p 就是 值比inputData大的第一个结点bigNode
			break;
		else{//如果没有找到,则p往链表的下一个结点进行遍历
			pre = p;//记录p结点的上一个结点
			p = p->next;
		}
	}
					
	if(p != NULL)//如果找到了
	{
		#ifdef  DEBUG
			printf("文件:%s 当前函数:%s 第%d行 找到了\\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		
		//找到的结点bigNode也就是 p 是首结点,使用头插
		if(p == head)
		{
			newNode->next = head;
			head = newNode;
		}
		else{
			//找到的结点bigNode 是中间结点,使用中间插法
			newNode->next = p;
			pre->next = newNode;
		}
	}
	else{//如果没找到 ,也就是说 p == NULL 
		#ifdef  DEBUG
			printf("文件:%s 当前函数:%s 第%d行 没找到\\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		//说明新结点是最大的,那么使用尾插
		pre->next = newNode;
	}
	
	return head;				
}

   

、在已知的链表中删除 值为 delData的结点

/*
delete_nodeToList  在已知的链表中删除 值为 delData的结点
参数:	
		head     链表的首结点
		delData  你要删除的结点的源数据
返回值:
		返回  链表的首结点
*/
struct node* delete_nodeToList(struct node *head,ElemType delData)
{
	//1、遍历链表,找到值为delData的结点(待删除的结点) 和 待删除结点的上一个结点
	struct node *p=head;
	struct node *pre=NULL;//待删除结点的上一个结点
	
	while(p)
	{
		if(p->data == delData)//找到了
		{
			if(p == head)//如果待删除的结点是首结点 p和head 都是存储首结点的地址
			{
				//1、先更新首结点
				head = head->next; //p->next;
				//2、待删除结点的next赋值为NULL
				p->next = NULL;
				//3、释放待删除结点的内存空间 p == 0x1010
				free(p); //p == 0x1010		
				//p = NULL;
				
				p = head;
			}
			else{//待删除结点在中间 ,也就是中间结点 //p 此时就是待删除结点  pre待删除结点的上一个结点
				//1、待删除结点的上一个结点指向待删除结点的下一个结点
				pre->next = p->next;
				//2、待删除结点的next赋值为NULL
				p->next = NULL;
				//3、释放待删除结点的内存空间
				free(p); 
				
				p = pre->next;
			}	
		}
		else{
			pre = p;
			p = p->next;
		}
	}
	
	return head;
}

以上是关于数据结构第三章:不带头结点的单链表操作的主要内容,如果未能解决你的问题,请参考以下文章

带头结点的单链表操作说明

编写不带头结点单链表的插入操作和删除操作算法

什么叫带头结点的链表? 什么叫不带头结点的链表?

单链表(不带头结点)按位序插入

C语言实现单链表(带头结点)的基本操作

数据结构不带头结点非循环的单链表