linuxC/C++单向循环链表:增、删、改、查、连接、反转详解

 

结构声明:

//类型声明
typedef int dataType;
struct list
{
	dataType data; //存放数据
	struct list * pNext;  //指向下一个结点
};
typedef struct list LIST;

头文件声明:

#ifndef _LINKCIRMAIN_H_
#define _LINKCIRMAIN_H_

//常量定义

enum E_RESULT
{
	ERROR = -1,
	SUCCESS,
	
	TAIL = -1,
	HEAD,
	
};

//类型声明
typedef int dataType;
struct list
{
	dataType data; //存放数据
	struct list * pNext;  //指向下一个结点
};
typedef struct list LIST;

//全局变量的声明 

//函数声明

/*
函数名: createList
函数功能:创建线性表
函数参数:无
函数返回值:成功时,返回指向线性表首地址的指针;失败时,返回NULL。
*/
LIST * createList();
/*
函数名: reverseList
函数功能:逆序一个单向循环链表
函数参数:无
函数返回值:成功时,返回新的指向线性表首地址的指针;失败时,返回NULL。
*/
LIST * reverseList(LIST * pList);
/*
函数名: catListSort
函数功能:连接两个已知尾节点的有序单向循环链表
函数参数:无
函数返回值:成功时,返回新的指向线性表首地址的指针;失败时,返回NULL。
*/
LIST * catListSort(LIST * pTail1,LIST *pTail2);

/*
求循环链表的尾部
*/
LIST * GetTail(LIST * pList);

/*
	连接两个已知的尾节点单向循环链表
*/
LIST * catList(LIST * pTail1,LIST *pTail2);


/*
函数名: insertDataToList
函数功能:给线性表指定位置插入数据
函数参数:
	LIST * pList : 线性表首地址
	int offset : 插入的位置, offset为0表示头插,offset为-1表示尾插。
	dataType newData : 准备插入的数据
函数返回值:成功时,返回0;失败时,返回-1。
*/
int insertDataToList ( LIST * pList, int offset, dataType newData );

/*
函数名: showList
函数功能:显示线性表中元素
函数参数:LIST * pList : 线性表首地址
函数返回值:无
*/
void showList ( LIST * pList );

/*
函数名: destroyList
函数功能:销毁线性表
函数参数:LIST * pList : 线性表首地址
函数返回值:无
*/
void destroyList ( LIST * pList );

/*
函数名:deleteDataFromList
函数功能:从线性表删除一个元素
函数参数:
	LIST * pList : 线性表首地址
	int offset : 删除的位置, offset为0表示头删,offset为-1表示尾删。
	dataType * pData : 保存被删除元素
函数返回值:成功时,返回0;失败时,返回-1。
*/
int deleteDataFromList ( LIST * pList, int offset, dataType * pData );

/*
函数名: searchDataFromList
函数功能:从线性表中查找元素
函数参数:
	LIST * pList : 线性表首地址
	dataType data : 要查找的元素
函数返回值:成功时,返回被查找元素的位置;失败时,返回-1。//约定首结点下标为0
*/
int searchDataFromList ( LIST * pList, dataType data );  

/*
函数名: updateData
函数功能:修改线性表中元素的值
函数参数:
	LIST * pList : 线性表首地址
	dataType oldData : 修改之前的元素
	dataType newData : 修改之后的元素
函数返回值:成功时,返回0;失败时,返回-1。
*/
int updateData ( LIST * pList, dataType oldData, dataType newData ); //p = p->pNext


#endif // _LIST_H_

操作实现:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "LinkCirMain.h"

/*
函数名: createList
函数功能:创建线性表
函数参数:无
函数返回值:成功时,返回指向线性表首地址的指针;失败时,返回NULL。
*/
LIST * createList()
{
	LIST * pList = NULL;
	
	pList = ( LIST * ) malloc ( sizeof( LIST ) );
	if (NULL != pList)
	{
		memset ( pList, 0, sizeof ( LIST ) );
		pList->pNext = NULL;
	}
	return pList;
}

/*
函数名: catListSort
函数功能:连接两个已知尾节点的有序从大到小单向循环链表
函数参数:无
函数返回值:成功时,返回新的指向线性表首地址的指针;失败时,返回NULL。
*/
LIST * catListSort(LIST * pTail1,LIST *pTail2)
{
	LIST *pTmp=NULL;
	LIST *pRtn=NULL;
	LIST *pDel=NULL;
	LIST *p1=NULL;
	LIST *p2=NULL;
	LIST *pt=NULL;
	if ( NULL == pTail1
	&&   NULL == pTail2)
	{
		return NULL;
	}else if(NULL == pTail1)//第一个为空返回第二个
	{
		pRtn = pTail2->pNext;
		return pRtn;
	}else if(NULL == pTail2)//第二个为空返回第一个
	{
		pRtn = pTail1->pNext;
		return pRtn;		
	}else if(pTail1->pNext->pNext->data <= pTail2->data)
	{//第一个的第一个元素(最大值)小于第二个的最小值那么直接追加
		printf("%d  %d\n",pTail1->pNext->pNext->data,pTail2->data);
		pDel = pTail1->pNext;
		pTail1->pNext =	pTail2->pNext;
		pTail2->pNext = pDel->pNext;		
		free(pDel);
		pDel=NULL;		
		return pTail1->pNext;
	}else if(pTail2->pNext->pNext->data <= pTail1->data)
	{//第二个的第一个元素(最大值)小于第一个的最小值那么直接追加
		pDel = pTail2->pNext;
		pTail2->pNext =	pTail1->pNext;
		pTail1->pNext=pDel->pNext;				
		free(pDel);
		pDel=NULL;
		return pTail2->pNext;
	}else
	{   //如果上述条件都不符合则 	//pList1 = 99, 88, 44, 33, 31  //pList2 = 77, 55, 45, 44
		//先保护首节点,也就是强制返回第一的首地址,将新的列表链到第一个链表的首地址之后
		pRtn=pTail1->pNext;
		//获取第一链表的第一个元素的地址
		p1 = pTail1->pNext->pNext;
		//获取第二链表的第一个元素的地址
		p2 = pTail2->pNext->pNext;
		//做一个指针标记点,用来标记新的链表的最后一个元素地址
		pt = pRtn;
		//获取将被要删除的第二个链表头节点
		pDel = pTail2->pNext;
		while(1)
		{			
			if(p1->data >= p2->data)
			{
				pt->pNext = p1;//如果第一个链表的某个元素大于第二个,那么将这个元素链到新链表中
				pt = p1;//移动做一个指针标记点,指向新链表最后的元素地址
				if(p1->pNext == pRtn)//如果等于首节点,那么是最后一个元素,则将另一个直接追加
				{
					p1->pNext = p2;
					pTail2->pNext = pRtn;//让另一个的尾节点指向首节点,完成循环链表
					free(pDel);
					pDel=NULL;
					return pRtn;
				}
				p1 = p1->pNext;	//向后移动指针			
			}
			
			if(p2->data > p1->data)
			{
				pt->pNext = p2;//如果第一个链表的某个元素大于第二个,那么将这个元素链到新链表中
				pt = p2;//移动做一个指针标记点,指向新链表最后的元素地址
				if(p2->pNext == pTail2->pNext)//如果等于首节点,那么是最后一个元素,则将另一个直接追加
				{
					p2->pNext = p1;
					pTail1->pNext = pRtn;//让另一个的尾节点指向首节点,完成循环链表					
					free(pDel);
					pDel=NULL;
					return pRtn;
				}
				p2 = p2->pNext;//向后移动指针
			}
		}
	}	
}
/*
函数名: reverseList
函数功能:逆序一个单向循环链表
函数参数:线性表首地址的指针
函数返回值:成功时,返回新的指向线性表首地址的指针;失败时,返回NULL。
*/
LIST * reverseList(LIST * pList)
{
	LIST *pRtn = NULL,*pFront = NULL,*qTmp=NULL;
	if ( NULL == pList)
	{
		return NULL;
	}
	pRtn=pList;//保存头节点
	pFront = pList->pNext;//保存第一个地址 
	pList->pNext = pList; //原有头指向 pList头节点
	while(pFront!=pList)  
	{   
		qTmp = pFront->pNext; //获取p之后的节点地址 
		//将第一个节点的指针域置空,当程序第一次进如循环,则第一个节点将会是最后
		pFront->pNext = pList->pNext;  
		pList->pNext = pFront; //将第一个节点(当前的节点链接到头节点),利用头插法实现逆置 
		pFront=qTmp;  //更新 ,将第二个节点(当前节点的后一个节点) 赋值给p
	} 
	return pRtn;
 }
/*
函数名: catList
函数功能:连接两个已知尾节点的单向循环链表
函数参数:无
函数返回值:成功时,返回新的指向线性表首地址的指针;失败时,返回NULL。
*/
LIST * catList(LIST * pTail1,LIST *pTail2)
{
	LIST *pTmp=NULL;
	LIST *pRtn=NULL;
	LIST *pDel=NULL;
	if ( NULL == pTail1
	&&   NULL == pTail2)
	{
		return NULL;
	}else if(NULL == pTail1)
	{
		pRtn = pTail2->pNext;
		return pRtn;
	}else if(NULL == pTail2)
	{
		pRtn = pTail1->pNext;
		return pRtn;		
	}else
	{
		pDel = pTail1->pNext;
		pTail1->pNext =	pTail2->pNext;
		pTail2->pNext=pDel->pNext;
		
		
		free(pDel);
		pDel=NULL;
	}	
	
	return pTail1->pNext;
}

/*
函数名: GetTail
函数功能:获取一个单向循环链表的尾巴
函数参数:无
函数返回值:成功时,返回尾巴;失败时,返回NULL。
*/
LIST * GetTail(LIST * pList)
{
	LIST * pTail = NULL;
	LIST *pTmp=NULL;
	if ( NULL == pList)
	{
		return NULL;
	}
	
	pTmp = pList->pNext;
	while(pList != pTmp->pNext)
	{
		pTmp=pTmp->pNext;
		//pTmp->pNext = pTmp->pNext;
	}
	//pTmp->pNext = pNew;		
	//让最后的尾节点的指针域指向头节点
	//pNew->pNext = pList;

	return pTmp;
}


/*
函数名: insertDataToList
函数功能:给线性表指定位置插入数据
函数参数:
	LIST * pList : 线性表首地址
	int offset : 插入的位置, offset为0表示头插,offset为-1表示尾插。
	dataType newData : 准备插入的数据
函数返回值:成功时,返回0;失败时,返回-1。
*/
int insertDataToList ( LIST * pList, int offset, dataType newData )
{
	LIST * pNew = NULL;
	LIST *pTmp=NULL;
	int index=1;
	if ( NULL == pList 
	||  offset < TAIL )
	{
		return ERROR;
	}
	
	//新建结点
	pNew = ( LIST * ) malloc ( sizeof ( LIST ) );
	if ( NULL == pNew )
	{
		return ERROR;
	}
	memset ( pNew, 0, sizeof ( LIST ) );
	pNew->data = newData ;
	pNew->pNext = NULL;

	if ( HEAD == offset )//头插法
	{	
		if(NULL == pList->pNext)
		{
			pList->pNext = pNew;
			pNew->pNext = pList;
		}else
		{
			//保护头结点之后的所有结点
			pNew->pNext = pList->pNext;		
			//连接新结点到头结点后面
			pList->pNext = pNew;
		}		
		return 0;
	}
	else if ( TAIL == offset )//尾插法
	{
		pTmp = pList->pNext;
		while(pList != pTmp->pNext)
		{
			pTmp=pTmp->pNext;
			//pTmp->pNext = pTmp->pNext;
		}
		pTmp->pNext = pNew;		
		//让最后的尾节点的指针域指向头节点
		pNew->pNext = pList;
		
		printf("今天的作业\r\n");
		return SUCCESS;
	}
	else 
	{
		pTmp=pList->pNext;
		while(pList != pTmp->pNext)
		{
			if(index == offset)
			{
				break;
			}
			index++;
			pTmp=pTmp->pNext;
			pTmp->pNext = pTmp->pNext;
		}
		if(pTmp != NULL && NULL != pTmp->pNext)
		{
			pNew->pNext=pTmp->pNext;
			pTmp->pNext = pNew;

		    printf("插入到中间%d的某个位置,今天的选做作业\r\n",index);
			return 0;
		}else
		{
			printf("您输入的位置已经超出链表长度\n");
			free(pNew);
			pNew=NULL;
			return -1;
		}
	}
	return SUCCESS;
}


/*
函数名: searchDataFromList
函数功能:从线性表中查找元素
函数参数:
	LIST * pList : 线性表首地址
	dataType data : 要查找的元素
函数返回值:成功时,返回被查找元素的位置;失败时,返回-1。//约定首结点下标为0
*/
int searchDataFromList ( LIST * pList, dataType data )  
{		
	int index=0;
	LIST *p=NULL;
	if(pList == NULL)
	{
		return -1;
	}
	p=pList->pNext;
	while(NULL != p)
	{		
		if(p->data == data)
		{
			return index;
		}
		index++;
		p = p->pNext;
	}
		
	return -1;
	
}


/*
函数名: showList
函数功能:显示线性表中元素
函数参数:LIST * pList : 线性表首地址
函数返回值:无
*/
void showList ( LIST * pList )
{
	LIST * p = NULL;
	
	if ( NULL == pList 
	||   NULL == pList->pNext )
	{
		return ;
	}
	
	p = pList->pNext;  
	
	while ( pList != p)
	{
		printf("%d --> ", p->data); 
		p = p->pNext;		
	}
	
	printf("^\r\n");
	return ;
}

/*
函数名: destroyList
函数功能:销毁线性表
函数参数:LIST * pList : 线性表首地址
函数返回值:无
*/
void destroyList ( LIST * pList )
{
	LIST * pDel = NULL;
	
	if ( NULL == pList )
		return ;
	while ( pList != pList->pNext )
	{
		//让pDel指向首结点
		pDel = pList->pNext;
		//保护pDel后的所有结点
		pList->pNext = pDel->pNext;
		//释放pDel
		free( pDel );
		pDel = NULL;
	}
	
	free( pList );
	pList = NULL;
	return ;
}

/*
函数名:deleteDataFromList
函数功能:从线性表删除一个元素
函数参数:
	LIST * pList : 线性表首地址
	int offset : 删除的位置, offset为0表示头删,offset为-1表示尾删。
	dataType * pData : 保存被删除元素
函数返回值:成功时,返回0;失败时,返回-1。
*/
int deleteDataFromList ( LIST * pList, int offset, dataType * pData )
{
	LIST * pDel = NULL;
	LIST *pTmp=NULL;
	int index=0;
	if ( NULL ==  pList 
	||   NULL ==  pList->pNext 
	||   offset < TAIL )
	{
		return ERROR;
	}
	
	if ( HEAD ==  offset )//删除首结点
	{
		//让pDel指向首结点
		pDel = pList->pNext;
		//保护pDel后的所有结点
		pList->pNext = pDel->pNext;
		//保存被删除元素
		if ( NULL != pData )
		{
			* pData = pDel->data;
		}
		//释放pDel
		free( pDel );
		pDel = NULL;
		return 0;
	}
	else if ( TAIL == offset )
	{
		pDel=pList->pNext;
		//删除尾结点 今天的作业\r\n
		while(NULL != pDel->pNext)
		{
			pTmp=pDel;
			pDel = pTmp->pNext;
			pDel->pNext = pDel->pNext;
		}
		
		pTmp->pNext=NULL;
		if ( NULL != pData )
		{
			* pData = pDel->data;
		}
		free(pDel);
		pDel=NULL;
		
		return 0;
	}
	else 
	{
		//今天的作业\r\n
		pDel=pList->pNext;
		while(NULL != pDel->pNext)
		{
			if(index == offset)
			{
				break;
			}
			index++;
			pTmp = pDel;
			pDel=pTmp->pNext;
			pDel->pNext = pDel->pNext;
		}
		if(pDel != NULL&& NULL != pDel->pNext)
		{
			if ( NULL != pData )
			{
				* pData = pDel->data;
			}
			pTmp->pNext=pDel->pNext;
			free(pDel);
			pDel=NULL;
			return 0;
		}else
		{
			printf("您输入的位置已经超出链表长度\n");
			return -1;
		}
	}
	return SUCCESS;
}

测试代码:

#include <stdio.h>
#include "LinkCirMain.h"

//函数的使用
int main()
{
	LIST * pList1 = NULL,*pList2 = NULL;
	LIST * pTail1 = NULL,*pTail2=NULL;
	LIST * pList3 = NULL;
	LIST * pList6 = NULL;
	LIST * pList7 = NULL;
	dataType data;
	int index=0;
	//创建链表
	pList1 = createList();
	if ( NULL == pList1 )
	{
		printf("create list1 error\r\n");
		return -1;
	}
	pList2 = createList();
	if ( NULL == pList2 )
	{
		printf("create list2 error\r\n");
		return -1;
	}
	
	//存放年龄 pList1
	insertDataToList ( pList1, 0, 31 );//插入位置起始为0
	insertDataToList ( pList1, 0, 33 );
	insertDataToList ( pList1, 0, 44 ); 
	insertDataToList ( pList1, 0, 88 ); 
	insertDataToList ( pList1, 0, 99 ); //1,2,3,4,5	
	//insertDataToList ( pList1, -1, 6 ); //尾插法
	
	//存放年龄 pList1
	//insertDataToList ( pList2, 0, 29 );//插入位置起始为0
	insertDataToList ( pList2, 0, 44 );
	insertDataToList ( pList2, 0, 45 ); 
	insertDataToList ( pList2, 0, 55 ); 
	insertDataToList ( pList2, 0, 77 );//11,22,33,44,55
	//insertDataToList ( pList2, -1, 66 ); //尾插法
		
	
	printf("pList1\n");
	showList ( pList1 );
	printf("pList2\n");
	showList ( pList2 );
	
	//printf("测试反转pList7\n");
	//pList7 = reverseList(pList1);
	//showList ( pList7 );	
	//return 0;
	
	
	
	pTail1 = GetTail(pList1);
	pTail2 = GetTail(pList2);
	
	printf("pList1 - %d\n",pTail1->data);
	printf("pList2 - %d\n",pTail2->data);
	
	//一个最小值大于另一个的最大值,做链接
	//pList1 = 1,2,3,4,5
	//pList1 = 11,22,33,44,55
	//pList6 = catListSort(pTail1,pTail2);
	//pList6 = catListSort(pTail2,pTail1);	
	
	//长度相等 
	//pList1 = 99, 88, 44, 33, 31
	//pList2 = 77, 55, 45, 44, 29
	//pList6 = catListSort(pTail1,pTail2);	
	//pList6 = catListSort(pTail2,pTail1);

	//长度不相等
	//pList1 = 99, 88, 44, 33, 31
	//pList2 = 77, 55, 45, 44
	//pList6 = catListSort(pTail1,pTail2);	
	pList6 = catListSort(pTail2,pTail1);
	
	printf("pList6\n");
	showList ( pList6 );
	
	//链接两个单向循环链表
	/*
	printf("pList4\n");
	pList4 = catList(NULL,pTail2);
	showList ( pList4 );
	
	printf("pList5\n");
	pList5 = catList(pTail1,NULL);
	showList ( pList5 );
	
	pList3 = catList(pTail1,pTail2);
	printf("pList3\n");
	showList ( pList3 );
	
	insertDataToList ( pList2, 2, 77 ); //尾插法
	showList ( pList3 );
	*/	
	
	
	//销毁顺序表
	destroyList ( pList3 );
	destroyList ( pList6 );
	pList1 = NULL;
	pList2 = NULL;
	pList3 = NULL;
	pList6 = NULL;
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值