C语言版数据结构中单链表的插入,查找,删除,排序与逆置

文章目录

前言

本文的函数定义,头文件,结构体类型与主函数
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct LINK{
	int data;
	struct LINK* next;
}*link;

link createlink(link );
void outlink(link );
void menu(link );
void deletelink(link );
link findlink(link );
void insertlink(link );
void deletelink1(link );
void deletelink2(link );
int puanduan(link ,int );
int link_length(link );
link findlink1(link );
void findlink2(link );
void turnlink(link );
int panduan2(link ,link );
bool is_empty(link );
void sortlink(link );
link comparelink(link );

int main(void)
{
	link phead;
	phead=createlink(phead);
	outlink(phead);
	system("pause");				                 // 暂停
	system("cls");									 // 清屏
	menu(phead);
	system("pause");
	return 0;
}


里面函数用法下面一一赘述.



一、创建单链表

该模块的函数代码为:

// 创建以随机数赋值进行创建
link createlink(link phead)
{
	link pend,body;
	phead=(link)malloc(sizeof(struct LINK));
	pend=phead;
	int length,i=0;
	printf("请输入链表长度:\n");
	scanf("%d",&length);
	srand(time(NULL));
	while(i<length)
	{
		body=(link)malloc(sizeof(LINK));
		body->data=rand()%101;
		pend->next=body;
		pend=body;
		i++;
	}
	pend->next=NULL;							//尾插			
	printf("链表创建成功!\n\n");
/*	phead->next=NULL;
	int length,i=0;
	printf("请输入链表长度:\n");
	scanf("%d",&length);
	while(i<length)
	{
		body=(link)malloc(sizeof(struct LINK));
		body->data=i+1;
		body->next=phead->next;
		phead->next=body;
		i++;
	}											//头插			*/
	return phead;
}

单链表的生成方式有两种:

1.头插法

代码块如下:

	link pend,body;
	phead=(link)malloc(sizeof(struct LINK));
	phead->next=NULL;
	int length,i=0;
	printf("请输入链表长度:\n");
	scanf("%d",&length);
	while(i<length)
	{
		body=(link)malloc(sizeof(struct LINK));
		body->data=i+1;
		body->next=phead->next;
		phead->next=body;
		i++;
	}
	return phead;

这里是以累加的数(i+1)为初始值.
头插法主要用法在于先生成一个头节点,然后每次的新节点都插在头节点的前一位,再将头节点放在链表的第一个位置,以此类推.


2.尾插法
代码块如下:

	link pend,body;
	phead=(link)malloc(sizeof(struct LINK));
	pend=phead;
	int length,i=0;
	printf("请输入链表长度:\n");
	scanf("%d",&length);
	srand(time(NULL));
	while(i<length)
	{
		body=(link)malloc(sizeof(LINK));
		body->data=rand()%101;
		pend->next=body;
		pend=body;
		i++;
	}
	pend->next=NULL;							//尾插			
	printf("链表创建成功!\n\n");
	return phead;

尾插法
此处尾插法主要是以随机数为初始值.
尾插法的主要写法在于:
将新节点放在当前链表的最后一个节点后面 .
注意:头节点不能往下移动,所以前代码中的pend代替phead往下移动;
每次加完新节点后,pend都得指向最后一个节点;
最后一个节点接入链表后,pend指向空指针.


本文使用尾插法


二、链表的输出

代码如下:

void outlink(link phead)
{
	link body=phead->next;
	if(body==NULL)
	{
		printf("当前为空表!\n");
		putchar(10);
		putchar(10);
		return;
	}
	int i=0;
	printf("\n----------------------------------------\n");
	printf("\n该链表的元素为:\n");
	while(body)
	{
		printf("%-6d",body->data);
		body=body->next;
		i++;
		if(i%5==0)						//每五个换一行
			putchar(10);
	}
	printf("\n----------------------------------------\n");
	putchar(10);											//进行换行操作,下面此写法不再说明
	putchar(10);
}

emm,这没啥好说的.


三、关于插,查,排,删,逆置的菜单

代码如下:

// 当前菜单以实现 插入 删除 查找 逆置 排序 ;
// 查找可返回元素位置(仅当选择以元素查找时) ;
void menu(link phead)
{
	link pnew;
	while(1)
	{
		printf("		----------------------------------------\n");
		printf("		-------------------menu-----------------\n");
		printf("		----------------1.链表插入--------------\n");
		printf("		----------------2.链表删除--------------\n");
		printf("		----------------3.链表查找--------------\n");
		printf("		----------------4.链表逆置--------------\n");
		printf("		----------------5.链表排序--------------\n");
		printf("		----------------0.退出菜单--------------\n");
		printf("		-------------------end------------------\n");
		printf("		----------------------------------------\n");
		printf("请输入选择:\n");
		int i;
		scanf("%d",&i);
		if(i==1)
		{
			insertlink(phead);
			system("pause");
			system("cls");					
		}
		else if(i==2)
		{
			deletelink(phead);
			system("pause");
			system("cls");
		}
		else if(i==3)
		{
			pnew=findlink(phead);
			system("pause");
			system("cls");
		}
		else if(i==0)
		{
			printf("已退出菜单!\n\n");
			return;
		}
		else if(i==4)
		{
			turnlink(phead);
			system("pause");
			system("cls");
		}
		else if(i==5)
		{
			sortlink(phead);
			system("pause");
			system("cls");
		}
		else 
		{
			printf("输入有误,需重新输入!\n");
			system("pause");
			system("cls");
		}
	}
}

以循环实现多次操作


四、关于链表的插入

代码如下:

// 插入以元素位置插入,用循环找到需要插入元素位置的上一个节点,在进行插入操作
void insertlink(link phead)
{
	int i=0,local;
	link body=phead;
	link pnew=(link)malloc(sizeof(struct LINK));
	outlink(phead);
	link_length(phead);
	printf("请输入要插入的元素位置:\n");
	scanf("%d",&local);
	while(body&&i<local)
	{
		if(i+1==local)
			break;
		body=body->next;
		i++;
	}											//寻找插入位置的前一节点
	if(i>=local||!body)
	{
		printf("输入位置有误!\n");
		return;
	}											//未找到,输出错误提示,并结束当前插入
	printf("请输入要插入的元素大小:\n");
	scanf("%d",&pnew->data);
	pnew->next=body->next;
	body->next=pnew;
	outlink(phead);								//输出插入后的新链表
}

这里的主要想法已经写道代码块中了,也不再赘述.


五、关于链表的删除

1.关于删除的方式

此处我分了按元素位置删除与按元素大小删除
下面函数的作用为 选择删除类型

// 此处仅为两种删除方式的选择函数
void deletelink(link phead)
{
	if(is_empty(phead))
	{
		printf("当前为空链表,请添加元素,否则无法删除!\n");
		return;
	}											//显然,空表不需要删除,直接结束删除

	printf("		---------------------------------------\n");
	printf("		---------------两种删除方式------------\n");
	printf("		---------------1.以元素删除------------\n");
	printf("		---------------2.以位置删除------------\n");
	printf("		---------------------------------------\n");
	printf("\n请输入你的选择:\n");
	int number;
	scanf("%d",&number);
	if(number==1)
	{
		deletelink1(phead);						// 进入方式1
	}
	else if(number==2)
	{
		deletelink2(phead);						// 进入方式2
	}
	else
	{
		printf("输入有误,重新开始删除!\n");
		deletelink(phead);
	}											//为了满足用户,用户输入错误选项后,
												//让用户重新进行删除选择
}

2.按元素大小删除

此方法适用于一个或多个相同元素的删除.
代码如下:

//						该方式1的删除中,主要想法如下:
//		1.判断删除的元素是否存在,若存在,进行下一步,若不存在,给出提示,退出删除
//		2.假定需删除的元素不止一个,在删除后不再终止循环,而是一直找到链表尾部
//	  (2补).在删除中应找到需要删除元素的前一个节点故为:body->next->data==number;
//	  (2补).并且在未找到应删元素时,而且在该元素之后没有节点时,退出删除;
//		3.此处谨防最后一个元素也为应删元素;但是前面(2补)中的方法不再适用,新加的办法
//		4.假如此时的链表只有一个有用节点,直接将该节点释放
void deletelink1(link phead)
{
	outlink(phead);
	printf("请输入需要删除的元素:\n");
	int number;
	scanf("%d",&number);
	if(puanduan(phead,number)==0)			// 1
	{
		printf("无此数!\n");
		putchar(10);
		putchar(10);
		return;
	}
	else if(puanduan(phead,number)==1)				// 2
	{
		if(phead->next->next!=NULL)
		{
			while(1)
			{
				link body=phead;
				while(body->next->data!=number && body->next->next)               //2补
					body=body->next;
				if(body->next->data!=number && NULL==body->next->next)
					break;
				if(phead->next->data==number && phead->next->next==NULL)		  //3
				{
					link p=body->next;
					printf("删除的元素为%d\n",phead->next->data);
					phead->next=NULL;
					free(p);
					break;
				}
				link p=body->next;
				printf("删除的元素为%d\n",p->data);
				body->next=body->next->next;
				free(p);
			}
			outlink(phead);
		}
		else																	//4
		{
			link p=phead->next;
			printf("删除的元素为%d\n",phead->next->data);						
			phead->next=NULL;
			free(p);
			outlink(phead);
		}
	}
}

说明已经放入代码块中.

3.按照元素位置删除

代码如下:

// 当以元素位置删除时,需找到删除元素的前一个节点,并将该元素内存释放
void deletelink2(link phead)
{
	outlink(phead);
	int length=link_length(phead);
	printf("请输入需要删除的元素位置:\n");
	int local,i=1;
	scanf("%d",&local);
	link body=phead;
	if(i>local || local>length)						//判断输入位置是否合法
	{
		printf("元素位置有误!\n\n\n");
		return;
	}
	while(i<local && body->next)
	{
		body=body->next;
		i++;
	}
	link p=body->next;
	printf("删除的元素为%d\n",p->data);
	body->next=body->next->next;
	free(p);
	outlink(phead);
}

emm,这个也不多作赘述,就是找到需要删除的元素位置,将该位置的前一个节点的指针域存入需要删除元素的下一个节点的位置.


六、关于链表的查找

1.查找的方式

为了避免争议,查找我也分为了按元素大小查找与元素位置查找
代码如下:

//此时也仅为选择两种查找方式
link findlink(link phead)
{
	printf("		---------------------------------------\n");
	printf("		---------------两种查找方式------------\n");
	printf("		---------------1.以元素查找------------\n");
	printf("		---------------2.以位置查找------------\n");
	printf("		---------------------------------------\n");
	printf("\n请输入你的选择:\n");
	int number;
	scanf("%d",&number);
	if(number==1)							//当方式1找到同个元素的多个位置时,将位置存入
											//链表,并且返回菜单;
	{
		link pnew=findlink1(phead);
		if(pnew!=NULL)
			printf("已将元素位置存入链表中!\n\n\n");
		return pnew;
	}
	else if(number==2)
	{
		findlink2(phead);
	}
	else
	{
		printf("输入有误,重新开始查找!\n");
		findlink(phead);
	}										//提醒用户输入选择有误,重新查找
}

2.按元素大小查找

这也可适用与多个与一个相同元素的查找,当找到元素位置时存入一个链表中,并在结束时将该链表返回到菜单中,供插入,删除使用.
代码如下:

//						     		查找方式1的主要想法:
//		1.查找时,在前判断函数中先判断有无此数;(也可借此判断链表是否为空)
//									  在有该数的前提下
//		2.此时需查找元素可能不止一个,那么一直查找到链表末尾,并将找得的位置依次存入新链表pnew
//		3.输入pnew中的查找到的元素位置信息
//		4.返回pnew,以便后续使用。
link findlink1(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return NULL;
	}
	outlink(phead);
	printf("请输入需要查找的元素:\n");
	int number,j=1;
	scanf("%d",&number);
	link body=phead->next;
	link pnew=(link)malloc(sizeof(struct LINK));
	link pend=pnew;
	if(puanduan(phead,number)==0)                      //1
	{
		printf("无此数!\n");
		putchar(10);
		putchar(10);
		return NULL;
	}
	else if(puanduan(phead,number)==1)
	{
		while(body)
		{
			if(body->data==number)
			{
				link pbody=(link)malloc(sizeof(struct LINK));
				pbody->data=j;
				pend->next=pbody;
				pend=pbody;
			}
			j++;
			body=body->next;
		}											  //2
	}
	pend->next=NULL;
	printf("\n该元素位置为:\n");
	body=pnew->next;
	while(body)
	{
		printf("%-5d",body->data);
		body=body->next;
	}												 //3
	putchar(10);
	putchar(10);
	return pnew;								     //4
}

主要思想看代码注释,里面的pnew存放的是元素位置(尾插法).
其中puanduan函数是判断被查找链表中是否有该元素.

3.按元素位置查找

代码如下:

// 该方式为以元素位置查找元素;遍历到该元素位置,直接输出该元素。
void findlink2(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return;
	}
	link body=phead->next;
	int length=link_length(phead);
	printf("请输入需要查找的元素位置:\n");
	int local;
	scanf("%d",&local);
	int i=0;
	if(local<1||local>length)
	{
		printf("\n输入位置有误!\n\n\n");
		return;
	}
	while(i<local-1)
	{
		body=body->next;
		i++;
	}
	printf("\n该位置元素为:%d\n\n",body->data);
}

和删除插入时查找元素思想差不多.


七、关于链表的逆置

代码如下:

//									逆置链表的主要想法
//		1.若该链表为空时,给出提示,不逆置;仅有一个节点时,无需逆置
//							      当该链表不止一个节点时
//		2.将此前链表分为头结点(pnew)与头结点以后(body)两个部分
//		3.每次讲body以后的遍历到最后一个节点,并标记最后两个节点;把最后一个节点接入pnew后;
//		  原body倒数第二个节点指向空,pnew指向pnew节点的最后一个节点
//		4.当body中剩下最后一个节点时,不再遍历,直接连在pnew后;此时最后一个节点一定指向NULL
void turnlink(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return;
	}
	link body=phead->next,body1=body;
	link body2,pnew=phead;
	if(phead->next->next==NULL)
	{
		outlink(phead);
		return;
	}
	while(1)
	{
		while(body->next!=NULL)
		{
			body2=body;
			body=body->next;
		}
		body2->next=NULL;
		pnew->next=body;
		pnew=pnew->next;
		body=body1;
		if(body1->next==NULL)
			break;
	}
	pnew->next=body1;
	outlink(phead);
}

emm,我觉得我代码块里写的注释很详细(手动滑稽).


八、关于链表的排序

这里的排序是从大到小排序.
我用的方法为:
1.将原链表分为头节点(pnew)与头节点(pbody->next)以后的节点考虑;
2.每次都找到当前头节点(pbody)以后最大的数的节点(q),将头节点以后的第一个找到该数的位置删掉(不能释放).
3.再将该数的节点插入头节点以后的位置(q->next=pnew->next;pnew->next=q;),再将头节点移到这个刚接入的节点的位置(pnew=pnew->next).
4.以此类推,直到找到最后一个节点,退出循环(这里跳出循环条件就是头指针指向的最后一个位置为空).


具体代码如下:

void sortlink(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return;
	}
	link pnew=phead;
	link body=phead;
	while(1)
	{
		link q=comparelink(body->next);
		while(body->next)
		{
			if(body->next==q)
			{
				body->next=body->next->next;
				break;
			}
			body=body->next;
		}										//释放当前链表中的最大值
		q->next=pnew->next;
		pnew->next=q;
		pnew=pnew->next;						//将最大值插入当前链表中
		body=pnew;
		if(pnew->next==NULL)
			break;
	}
	outlink(phead);
}

// 依次找到当前链表中的最大值
link comparelink(link phead)
{
	link body=phead;
	link s=phead;
	while(body)
	{
		if(s->data<body->data)
			s=body;
		body=body->next;
	}
	return s;
}

其他排序我后续再想办法写写.


九、其他辅助函数与全部代码

这个判断链表是否空,是空返回true,不是返回false.

//  判断是否为空表(在删除元素时使用)
bool is_empty(link head)
{
	if(head->next==NULL)
		return true;
	else
		return false;
}	

下面是总的代码,可复制粘贴运行
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct LINK{
	int data;
	struct LINK* next;
}*link;

link createlink(link );
void outlink(link );
void menu(link );
void deletelink(link );
link findlink(link );
void insertlink(link );
void deletelink1(link );
void deletelink2(link );
int puanduan(link ,int );
int link_length(link );
link findlink1(link );
void findlink2(link );
void turnlink(link );
int panduan2(link ,link );
bool is_empty(link );
void sortlink(link );
link comparelink(link );

int main(void)
{
	link phead;
	phead=createlink(phead);
	outlink(phead);
	system("pause");				                 // 暂停
	system("cls");									 // 清屏
	menu(phead);
	system("pause");
	return 0;
}

// 创建以随机数赋值进行创建
link createlink(link phead)
{
	link pend,body;
	phead=(link)malloc(sizeof(struct LINK));
	pend=phead;
	int length,i=0;
	printf("请输入链表长度:\n");
	scanf("%d",&length);
	srand(time(NULL));
	while(i<length)
	{
		body=(link)malloc(sizeof(LINK));
		body->data=rand()%101;
		pend->next=body;
		pend=body;
		i++;
	}
	pend->next=NULL;							//尾插			
	printf("链表创建成功!\n\n");
/*	phead->next=NULL;
	int length,i=0;
	printf("请输入链表长度:\n");
	scanf("%d",&length);
	while(i<length)
	{
		body=(link)malloc(sizeof(struct LINK));
		body->data=i+1;
		body->next=phead->next;
		phead->next=body;
		i++;
	}											//头插			*/
	return phead;
}

void outlink(link phead)
{
	link body=phead->next;
	if(body==NULL)
	{
		printf("当前为空表!\n");
		putchar(10);
		putchar(10);
		return;
	}
	int i=0;
	printf("\n----------------------------------------\n");
	printf("\n该链表的元素为:\n");
	while(body)
	{
		printf("%-6d",body->data);
		body=body->next;
		i++;
		if(i%5==0)
			putchar(10);
	}
	printf("\n----------------------------------------\n");
	putchar(10);											//进行换行操作,下面此写法不再说明
	putchar(10);
}


// 当前菜单以实现 插入 删除 查找 逆置 排序 ;
// 查找可返回元素位置(仅当选择以元素查找时) ;
void menu(link phead)
{
	link pnew;
	while(1)
	{
		printf("		----------------------------------------\n");
		printf("		-------------------menu-----------------\n");
		printf("		----------------1.链表插入--------------\n");
		printf("		----------------2.链表删除--------------\n");
		printf("		----------------3.链表查找--------------\n");
		printf("		----------------4.链表逆置--------------\n");
		printf("		----------------5.链表排序--------------\n");
		printf("		----------------0.退出菜单--------------\n");
		printf("		-------------------end------------------\n");
		printf("		----------------------------------------\n");
		printf("请输入选择:\n");
		int i;
		scanf("%d",&i);
		if(i==1)
		{
			insertlink(phead);
			system("pause");
			system("cls");					
		}
		else if(i==2)
		{
			deletelink(phead);
			system("pause");
			system("cls");
		}
		else if(i==3)
		{
			pnew=findlink(phead);
			system("pause");
			system("cls");
		}
		else if(i==0)
		{
			printf("已退出菜单!\n\n");
			return;
		}
		else if(i==4)
		{
			turnlink(phead);
			system("pause");
			system("cls");
		}
		else if(i==5)
		{
			sortlink(phead);
			system("pause");
			system("cls");
		}
		else 
		{
			printf("输入有误,需重新输入!\n");
			system("pause");
			system("cls");
		}
	}
}


// 插入以元素位置插入,用循环找到需要插入元素位置的上一个节点,在进行插入操作
void insertlink(link phead)
{
	int i=0,local;
	link body=phead;
	link pnew=(link)malloc(sizeof(struct LINK));
	outlink(phead);
	link_length(phead);
	printf("请输入要插入的元素位置:\n");
	scanf("%d",&local);
	while(body&&i<local)
	{
		if(i+1==local)
			break;
		body=body->next;
		i++;
	}											//寻找插入位置的前一节点
	if(i>=local||!body)
	{
		printf("输入位置有误!\n");
		return;
	}											//未找到,输出错误提示,并结束当前插入
	printf("请输入要插入的元素大小:\n");
	scanf("%d",&pnew->data);
	pnew->next=body->next;
	body->next=pnew;
	outlink(phead);								//输出插入后的新链表
}


// 此处仅为两种删除方式的选择函数
void deletelink(link phead)
{
	if(is_empty(phead))
	{
		printf("当前为空链表,请添加元素,否则无法删除!\n");
		return;
	}											//显然,空表不需要删除,直接结束删除

	printf("		---------------------------------------\n");
	printf("		---------------两种删除方式------------\n");
	printf("		---------------1.以元素删除------------\n");
	printf("		---------------2.以位置删除------------\n");
	printf("		---------------------------------------\n");
	printf("\n请输入你的选择:\n");
	int number;
	scanf("%d",&number);
	if(number==1)
	{
		deletelink1(phead);						// 进入方式1
	}
	else if(number==2)
	{
		deletelink2(phead);						// 进入方式2
	}
	else
	{
		printf("输入有误,重新开始删除!\n");
		deletelink(phead);
	}											//为了满足用户,用户输入错误选项后,
												//让用户重新进行删除选择
}

//  判断是否为空表(在删除元素时使用)
bool is_empty(link head)
{
	if(head->next==NULL)
		return true;
	else
		return false;
}							


//						该方式1的删除中,主要想法如下:
//		1.判断删除的元素是否存在,若存在,进行下一步,若不存在,给出提示,退出删除
//		2.假定需删除的元素不止一个,在删除后不再终止循环,而是一直找到链表尾部
//	  (2补).在删除中应找到需要删除元素的前一个节点故为:body->next->data==number;
//	  (2补).并且在未找到应删元素时,而且在该元素之后没有节点时,退出删除;
//		3.此处谨防最后一个元素也为应删元素;但是前面(2补)中的方法不再适用,新加的办法
//		4.假如此时的链表只有一个有用节点,直接将该节点释放
void deletelink1(link phead)
{
	outlink(phead);
	printf("请输入需要删除的元素:\n");
	int number;
	scanf("%d",&number);
	if(puanduan(phead,number)==0)			// 1
	{
		printf("无此数!\n");
		putchar(10);
		putchar(10);
		return;
	}
	else if(puanduan(phead,number)==1)				// 2
	{
		if(phead->next->next!=NULL)
		{
			while(1)
			{
				link body=phead;
				while(body->next->data!=number && body->next->next)               //2补
					body=body->next;
				if(body->next->data!=number && NULL==body->next->next)
					break;
				if(phead->next->data==number && phead->next->next==NULL)		  //3
				{
					link p=body->next;
					printf("删除的元素为%d\n",phead->next->data);
					phead->next=NULL;
					free(p);
					break;
				}
				link p=body->next;
				printf("删除的元素为%d\n",p->data);
				body->next=body->next->next;
				free(p);
			}
			outlink(phead);
		}
		else																	//4
		{
			link p=phead->next;
			printf("删除的元素为%d\n",phead->next->data);						
			phead->next=NULL;
			free(p);
			outlink(phead);
		}
	}
}

// 需删除的元素是否存在
int puanduan(link phead,int number)
{
	while(1)
	{
		link body=phead;
		while(body->next->data!=number && body->next->next)
			body=body->next;
		if(body->next->data!=number && NULL==body->next->next)
			return 0;
		else 
			return 1;
	}
}

// 当以元素位置删除时,需找到删除元素的前一个节点,并将该元素内存释放
void deletelink2(link phead)
{
	outlink(phead);
	int length=link_length(phead);
	printf("请输入需要删除的元素位置:\n");
	int local,i=1;
	scanf("%d",&local);
	link body=phead;
	if(i>local || local>length)						//判断输入位置是否合法
	{
		printf("元素位置有误!\n\n\n");
		return;
	}
	while(i<local && body->next)
	{
		body=body->next;
		i++;
	}
	link p=body->next;
	printf("删除的元素为%d\n",p->data);
	body->next=body->next->next;
	free(p);
	outlink(phead);
}

// 判断当前链表长度,该函数在查找时使用
int link_length(link phead)
{
	int i=0;
	link body=phead->next;
	while(body)
	{
		body=body->next;
		i++;
	}
	printf("当前链表长度为:%d\n",i);
	putchar(10);
	return i;
}

//此时也仅为选择两种查找方式
link findlink(link phead)
{
	printf("		---------------------------------------\n");
	printf("		---------------两种查找方式------------\n");
	printf("		---------------1.以元素查找------------\n");
	printf("		---------------2.以位置查找------------\n");
	printf("		---------------------------------------\n");
	printf("\n请输入你的选择:\n");
	int number;
	scanf("%d",&number);
	if(number==1)							//当方式1找到同个元素的多个位置时,将位置存入
											//链表,并且返回菜单;
	{
		link pnew=findlink1(phead);
		if(pnew!=NULL)
			printf("已将元素位置存入链表中!\n\n\n");
		return pnew;
	}
	else if(number==2)
	{
		findlink2(phead);
	}
	else
	{
		printf("输入有误,重新开始查找!\n");
		findlink(phead);
	}										//提醒用户输入选择有误,重新查找
}


//						     		查找方式1的主要想法:
//		1.查找时,在前判断函数中先判断有无此数;(也可借此判断链表是否为空)
//									  在有该数的前提下
//		2.此时需查找元素可能不止一个,那么一直查找到链表末尾,并将找得的位置依次存入新链表pnew
//		3.输入pnew中的查找到的元素位置信息
//		4.返回pnew,以便后续使用。
link findlink1(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return NULL;
	}
	outlink(phead);
	printf("请输入需要查找的元素:\n");
	int number,j=1;
	scanf("%d",&number);
	link body=phead->next;
	link pnew=(link)malloc(sizeof(struct LINK));
	link pend=pnew;
	if(puanduan(phead,number)==0)                      //1
	{
		printf("无此数!\n");
		putchar(10);
		putchar(10);
		return NULL;
	}
	else if(puanduan(phead,number)==1)
	{
		while(body)
		{
			if(body->data==number)
			{
				link pbody=(link)malloc(sizeof(struct LINK));
				pbody->data=j;
				pend->next=pbody;
				pend=pbody;
			}
			j++;
			body=body->next;
		}											  //2
	}
	pend->next=NULL;
	printf("\n该元素位置为:\n");
	body=pnew->next;
	while(body)
	{
		printf("%-5d",body->data);
		body=body->next;
	}												 //3
	putchar(10);
	putchar(10);
	return pnew;								     //4
}


// 该方式为以元素位置查找元素;遍历到该元素位置,直接输出该元素。
void findlink2(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return;
	}
	link body=phead->next;
	int length=link_length(phead);
	printf("请输入需要查找的元素位置:\n");
	int local;
	scanf("%d",&local);
	int i=0;
	if(local<1||local>length)
	{
		printf("\n输入位置有误!\n\n\n");
		return;
	}
	while(i<local-1)
	{
		body=body->next;
		i++;
	}
	printf("\n该位置元素为:%d\n\n",body->data);
}


//									逆置链表的主要想法
//		1.若该链表为空时,给出提示,不逆置;仅有一个节点时,无需逆置
//							      当该链表不止一个节点时
//		2.将此前链表分为头结点(pnew)与头结点以后(body)两个部分
//		3.每次讲body以后的遍历到最后一个节点,并标记最后两个节点;把最后一个节点接入pnew后;
//		  原body倒数第二个节点指向空,pnew指向pnew节点的最后一个节点
//		4.当body中剩下最后一个节点时,不再遍历,直接连在pnew后;此时最后一个节点一定指向NULL
void turnlink(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return;
	}
	link body=phead->next,body1=body;
	link body2,pnew=phead;
	if(phead->next->next==NULL)
	{
		outlink(phead);
		return;
	}
	while(1)
	{
		while(body->next!=NULL)
		{
			body2=body;
			body=body->next;
		}
		body2->next=NULL;
		pnew->next=body;
		pnew=pnew->next;
		body=body1;
		if(body1->next==NULL)
			break;
	}
	pnew->next=body1;
	outlink(phead);
}

void sortlink(link phead)
{
	if(is_empty(phead))
	{
		printf("空链表!!\n\n");
		return;
	}
	link pnew=phead;
	link body=phead;
	while(1)
	{
		link q=comparelink(body->next);
		while(body->next)
		{
			if(body->next==q)
			{
				body->next=body->next->next;
				break;
			}
			body=body->next;
		}										//释放当前链表中的最大值
		q->next=pnew->next;
		pnew->next=q;
		pnew=pnew->next;						//将最大值插入当前链表中
		body=pnew;
		if(pnew->next==NULL)
			break;
	}
	outlink(phead);
}

// 依次找到当前链表中的最大值
link comparelink(link phead)
{
	link body=phead;
	link s=phead;
	while(body)
	{
		if(s->data<body->data)
			s=body;
		body=body->next;
	}
	return s;
}

结语


其实吧,这是我第一次在csdn里上传我写的代码,其实我写这个的初衷是为了和大家分享自己的一些思路,听取他人的意见,弥补自己不足(本人刚开始接触数据结构,是个在校大学生)。初来咋到,不足处还望各位海涵,如果代码中有什么不好,或者不对的用法,欢迎在评论区留言,一起讨论,一起进步,谢谢大家.
上一篇:多线程之无锁队列


下一篇:JZ15反转链表