服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言实现单链表的快速排序算法

C语言实现单链表的快速排序算法

2022-08-31 16:20CUP-GYC C/C++

大家好,本篇文章主要讲的是C语言实现单链表的快速排序算法,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

背景

传统QuickSort算法最大不足之处在于,由于其基于可索引存储结构设计(一般为数组或索引表),因而无法用于链式存储结构,而链式存储结构的实际应用非常广泛,例如动态存储管理、动态优先级调度等等,故本文针对于单向链表,以QuickSort的分治策略为基础,提出一种可用于单向链表的快速排序算法。

 

设计思路

将单向链表的首节点作为枢轴节点,然后从单向链表首部的第二个节点开始,逐一遍历所有后续节点,并将这些已遍历节点的key与枢轴节点的key进行比较,根据比较结果,重新将这些节点链接为less和more两个单向链表,less中所包含节点的key均小于枢轴节点的 key;more中所包含节点的key均大于或等于枢轴节点的key。然后再对得到的两个单链表进行递归操作,将进行内部递归排序最后连接到枢轴上。同时为达到在每次划分后将规模更小的两个单向链表链接到枢轴节点上,必须记录各自的尾节点位置,即需要设置两个指向尾节点的指针。less链表的首节点指针设定为lessHead,尾节点指针设定为lessTail;more链表的首节点指针设定为 moreHead,尾节点指针设定为moreTail。当前正在遍历的节点指针设定为current。当单向链表遍历结束后,亦即完成了一趟划分, 如此递归进行,便可完成整个单向链表的排序。除此之外,为了简化将 less和more单向链表链接到枢轴节点前、后部的过程,还需设定两个指向单向链表尾节点的指针 lessTail和moreTail。在递归过程中,得到的单链表的长度会依次减小,直到长度减小到一的时候即为递归出口。

 

算法主要步骤

步骤1:算法接收两个指针,其中listHead指 向单向链表首节点,listTail为空指针,划分过程中,listTail将指向单向链表的尾节点,划分后用于链接less单向链表到枢轴节点前。
步骤2:如果单向链表listHead仅有一个节点,则说明已有序,本层递归结束,返回listHead。
步骤3:令lessHead、lessTail、moreHead和 moreTail为空,令current为listHead的next域,即单向链表的第二个节点。
步骤4:如果current节点为空,则转入步骤13。
步骤5:如果current节点的key小于枢轴节点(即listHead)的key,则current节点应链接到 less单向链表,转入步骤6;否则,current节点应链 接到more单向链表,转入步骤9。
步骤6:修改lessTail指针使其指向current 节点。如果lessHead为空,则转入步骤7;否则转入步骤8。
步骤7:将less节点链接为单链表的首节点。
步骤8:将current节点链接为less单链表的尾结点;
步骤9:修改moreTail指针使其指向current 节点。如果moreHead为空,则转入步骤10;否则转入步骤11。
步骤10:将currnet节点链接为more单向链表的首节点。
步骤11:将currnet节点链接为more单向链表的尾节点。
步骤12:将current节点移动到单向链表的下一个节点。
步骤13:如果more单向链表不为空,则转入步骤14;否则转入步骤18。
步骤14:标记more单向链表的结束位置,即 置moreTail的next域为空。
步骤15:递归调用本算法,继续划分more单 向链表,传人moreHead和moreTail。步骤16将经过递归排序的more单向链表 链接到枢轴节点后。
步骤17:修改listTail指针使其指向more— Tail,以便本层递归结束后供上层递归过程使用。
步骤18:由于more单向链表为空,则枢轴节 点便是尾节点,即置listHead的next域为空。 步骤19:修改listTail指针使其指向listHead。
步骤20:如果less单向链表不为空,则转入 步骤21;否则转入步骤24。
步骤21:标记less单向链表的结束位置,即 置lessTail的next域为空。
步骤22:递归调用本算法,继续划分less单 向链表,传人lessHead和lessTail。 步骤23将经过递归排序的less单向链表链 接到枢轴节点前。
步骤24:由于less单向链表为空,则枢轴节 点便是首节点,即置lessHead为listHead。
步骤25:本层递归结束,返回lessHead。
示意图如下:

C语言实现单链表的快速排序算法

C语言实现单链表的快速排序算法

C语言实现单链表的快速排序算法

 

快速排序算法实现

Linklist Quicksort(Linklist *listHead, Linklist *listTail)
{
	Lnode *current;
	Lnode* lessHead = NULL, *lessTail = NULL, *moreHead = NULL, *moreTail = NULL;
	current = (*listHead)->next;//每次取首节点为枢纽,current指向第二个节点用于遍历
	if ((*listHead)->next != NULL)//当链表节点数不为1时(说明链表未排好序)
	{
		for (current = (*listHead)->next; current; current = current->next)
		{
			if (current->key < (*listHead)->key)
			{
				if (lessHead == NULL)
					lessHead = current;
				else
					lessTail->next = current;
				lessTail = current;
			}//current结点key小于枢纽key时放入less链表
			else
			{
				if (moreHead == NULL)
					moreHead = current;
				else
					moreTail->next = current;
				moreTail = current;
			}//current结点key大于枢纽key时放入more链表
		}
		//根据枢纽结点将T链表分为less和more两个链表
		if (moreTail)
			moreTail->next = NULL;
		if (lessTail)
			lessTail->next = NULL;
		//将more链表尾结点next域置空
		if (moreHead != NULL)
		{
			moreTail->next = NULL;
			Quicksort(&moreHead, &moreTail);
			(*listHead)->next = moreHead;
			*listTail = moreTail;
		}
		//若moreHead不空,则current为more链表的尾结点,对more链表进行递归处理,将more链表接在枢纽节点后
		else
		{
			(*listHead)->next = NULL;
			*listTail = *listHead;
		}
		//若moreHead为空,则只有less链表(即结点key全小于枢纽),将枢纽结点接在less节点后
		if (lessHead != NULL)
		{
			lessTail->next = NULL;
			Quicksort(&lessHead, &lessTail);
			lessTail->next = *listHead;
			*listHead = lessHead;
		}
		//若lesseHead不空,对less链表进行递归处理,再将枢纽节点接在less链表后
		else
		{
			lessHead = *listHead;
		}
		//若lesseHead为空,则枢纽结点作为首节点
		return lessHead;
	}
	else
		return *listHead;
}

 

整个程序源代码

#include<stdio.h>
#include<malloc.h> 
typedef struct Lnode
{
	int key;
	struct Lnode* next;
}Lnode, *Linklist;
//链表结构体类型
Linklist createList(Linklist L, int n)
{
	L = (Linklist)malloc(sizeof(Lnode));
	L->next = NULL;
	Lnode *p, *r;
	r = L;
	p = (Lnode*)malloc(sizeof(Lnode));
	scanf("%d", &r->key);
	for (int i = 1; i < n; i++)
	{
		p = (Lnode*)malloc(sizeof(Lnode));
		scanf("%d", &p->key);
		r->next = p;
		r = p;
	}
	r->next = NULL;
	return L;
}
//初始初始化及尾插法(正序)创建单链表
Linklist getTail(Linklist L)
{
	while (L->next)
		L = L->next;
	return L;
}
//得到尾指针
void Print(Linklist L)
{
	Lnode *p;
	p = L;
	while (p)
	{
		printf("%d ", p->key);
		p = p->next;
	}
}
//遍历单链表
Linklist Quicksort(Linklist *listHead, Linklist *listTail)
{
	Lnode *current;
	Lnode* lessHead = NULL, *lessTail = NULL, *moreHead = NULL, *moreTail = NULL;
	current = (*listHead)->next;//每次取首节点为枢纽,current指向第二个节点用于遍历
	if ((*listHead)->next != NULL)//当链表节点数不为1时(说明链表未排好序)
	{
		for (current = (*listHead)->next; current; current = current->next)
		{
			if (current->key < (*listHead)->key)
			{
				if (lessHead == NULL)
					lessHead = current;
				else
					lessTail->next = current;
				lessTail = current;
			}//current结点key小于枢纽key时放入less链表
			else
			{
				if (moreHead == NULL)
					moreHead = current;
				else
					moreTail->next = current;
				moreTail = current;
			}//current结点key大于枢纽key时放入more链表
		}
		//根据枢纽结点将T链表分为less和more两个链表
		if (moreTail)
			moreTail->next = NULL;
		if (lessTail)
			lessTail->next = NULL;
		//将more链表尾结点next域置空
		if (moreHead != NULL)
		{
			moreTail->next = NULL;
			Quicksort(&moreHead, &moreTail);
			(*listHead)->next = moreHead;
			*listTail = moreTail;
		}
		//若moreHead不空,则current为more链表的尾结点,对more链表进行递归处理,将more链表接在枢纽节点后
		else
		{
			(*listHead)->next = NULL;
			*listTail = *listHead;
		}
		//若moreHead为空,则只有less链表(即结点key全小于枢纽),将枢纽结点接在less节点后
		if (lessHead != NULL)
		{
			lessTail->next = NULL;
			Quicksort(&lessHead, &lessTail);
			lessTail->next = *listHead;
			*listHead = lessHead;
		}
		//若lesseHead不空,对less链表进行递归处理,再将枢纽节点接在less链表后
		else
		{
			lessHead = *listHead;
		}
		//若lesseHead为空,则枢纽结点作为首节点
		return lessHead;
	}
	else
		return *listHead;
}
int main()
{
	Lnode* L = NULL;
	int n;
	printf("请输入元素个数
");
	scanf("%d", &n);
	printf("请输入元素
");
	L = createList(L, n);
	Lnode* listTail;
	listTail = getTail(L);
	Quicksort(&L, &listTail);
	printf("排序后元素序列为
");
	Print(L);
	return 0;
}

整个程序已在Visual Studio 2017上运行通过

 

测试案例

(1)一般数据样例

C语言实现单链表的快速排序算法

(2)只有一个数据时

C语言实现单链表的快速排序算法

(2)有重复数据时

C语言实现单链表的快速排序算法

 

总结

到此这篇关于C语言实现单链表的快速排序算法的文章就介绍到这了,更多相关C语言快速排序算法内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/GeBrother/article/details/122587958

延伸 · 阅读

精彩推荐
  • C/C++C语言中do-while语句的2种写法示例

    C语言中do-while语句的2种写法示例

    这篇文章主要给大家介绍了关于C语言中do-while语句的2种写法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需...

    Spiritinme11842021-09-17
  • C/C++C++中需要注意的细节你知道吗

    C++中需要注意的细节你知道吗

    这篇文章主要介绍了C++ 需要注意的几点细节,帮助大家更好的理解和学习C++,感兴趣的朋友可以了解下,希望能够给你带来帮助...

    睡不饱的小默4282022-01-07
  • C/C++C语言中求字符串长度的函数的几种实现方法

    C语言中求字符串长度的函数的几种实现方法

    这篇文章主要介绍了C语言中求字符串长度的函数的几种实现方法,需要的朋友可以参考下...

    ZWE76161758122021-06-30
  • C/C++c语言读取txt文件内容简单实例

    c语言读取txt文件内容简单实例

    在本篇文章里小编给大家整理的是关于c语言如何读取txt文件内容,需要的朋友们可以参考下。...

    12292021-08-23
  • C/C++C++实现简单的信息管理系统

    C++实现简单的信息管理系统

    这篇文章主要为大家介绍了C++实现简单的信息管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    仙桃李远航6362021-03-30
  • C/C++C/C++实现快速排序算法的两种方式实例

    C/C++实现快速排序算法的两种方式实例

    快速排序是一种采用分治思想,在实践中通常运行较快一种排序算法,这篇文章主要给大家介绍了关于C/C++实现快速排序的两种方式的相关资料,文中给出了详...

    你的代码没bug8472021-12-14
  • C/C++C语言实现三子棋实例代码

    C语言实现三子棋实例代码

    大家好,本篇文章主要讲的是C语言实现三子棋实例代码,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览...

    永恒的爱与殇3702022-08-10
  • C/C++C语言关键字union的定义和使用详解

    C语言关键字union的定义和使用详解

    这篇文章主要介绍了C语言关键字union的定义和使用详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    沐歌爱编程4822021-10-21