快排与归并的算法(非递归版)

一.快排

1.递归法(方法多样)

1>hoare版

注:该方法小编已经在上篇博客中介绍过了,就不在这里过多赘述了,如果有兴趣的小伙伴可以看看小编的上篇博客哦

2>挖坑法

1)方法介绍:定义最左边的数据为key,此时最左边的位置内可视为没有数据(即被挖了个坑),定义L,R两个下标,分别位于最左侧和最右侧,R向前走,若找到比key小的数据停下来,将该处数据放在坑位中,这时R指向的位置成为新坑;L开始向后走,若找到比key大的数据停下来,将该处数据放在坑位中,这时L指向的位置成为新坑;当R与L相遇时,将key放在相遇位置的坑中,此时完成依次排序,下面将数据分成[left,key-1],[key+1,right]两个区间进行下一轮的排序,直至排序完成

2)时间复杂度:O(N*logN)

空间复杂度:O(1)

3)代码实现

复制代码
int qSortWay2(int* a, int left, int right)
{
	int key = a[left];
	int begin = left, end = right;
	while (begin < end)
	{
		while (begin<end && a[end] > key)
		{
			end--;
		}
		a[begin] = a[end];
		while (begin<end && a[begin] < key)
		{
			begin++;
		}
		a[end] = a[begin];
	}
	a[begin] = key;
    return begin;
}

3>前后指针法

1)方法介绍:定义prev,cur两个下标,prev指向key所在位置,cur指向prev的下一个位置,cur向后走,如果找到比key小的数据,先将prev++,再将cur,prev所在位置的数据交换,cur继续向后找比key小的数据,直至cur越界访问数据,返回prev作为下次排序的分割点下标

2)时间复杂度:O(N*logN)

空间复杂度:O(1)

3)代码实现

复制代码
int qSortWay3(int* a, int left, int right)
{
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
			Swap(&a[cur], &a[prev]);
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	return prev;
}

2.非递归法

1>方法介绍:利用栈将每个区间的左右下标分别入栈,待数据被细分到只有左下标>=右下标时,开始将左右下标出栈,进行排序

2>使用非递归法可以大大降低栈的消耗,但不一定能提高效率

1)利用栈模拟递归法实现非递归排序类似于二叉树的前序遍历

2)利用队列模拟递归法实现非递归排序类似于二叉树的层序遍历(利用队列可能无法实现排序,且空间消耗很大,不推荐使用)

3>代码实现

复制代码
void QuickSortNonR(int* a, int left,int right)
{
	ST st;
	STInit(&st);
	STPush(&st, right);
	STPush(&st, left);
	while (!STEmpty(&st))
	{
		int begin = STTop(&st);
		STPop(&st);
		int end = STTop(&st);
		STPop(&st);
		int keyi = qSortWay3(a, begin, end);
		//[begin,keyi-1],keyi,[keyi+1,end]
		if (keyi+1 < end)
		{
			STPush(&st, end);
			STPush(&st, keyi + 1);
		}
		if (begin < keyi - 1)
		{
			STPush(&st, keyi - 1);
			STPush(&st, begin);
		}
	}
	STDestory(&st);
}

二.归并(非递归法)

1.方法介绍

1)利用gap对数据从小区间到大区间进行归并(类似于将归并的递归方法用循环的方式进行从底层到顶层的排序),同时对两组数据[begin,begin+gap-1],[begin+gap,begin+2*gap-1]归并

2)gap从1开始,实现11归并,再2倍增加

3)注意此时存在越界访问的分风险,此时可以采用如下方法进行避免越界

2.时间复杂度:O(N*logN)

空间复杂度:O(N)

3.代码实现

复制代码
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	
	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			int j = i;
			//前一组最后一个数据下标大于n-1,则后面一组数据全部越界
			if (end1 >= n)
			{
				break;
			}
			//后一组最后一个数据下标大于n-1,则有部分数据越界,令尾巴等于n-1
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
		}
		gap = gap * 2;
	}
	

	free(tmp);
	tmp = NULL;
}
相关推荐
荒诞硬汉4 分钟前
数组常见算法
java·数据结构·算法
少许极端4 分钟前
算法奇妙屋(二十四)-二维费用的背包问题、似包非包问题、卡特兰数问题(动态规划)
算法·动态规划·卡特兰数·二维费用背包·似包非包
Z1Jxxx8 分钟前
日期日期日期
开发语言·c++·算法
万行15 分钟前
机器学习&第五章生成式生成器
人工智能·python·算法·机器学习
罗湖老棍子17 分钟前
【模板】并查集(洛谷P3367)
算法·图论·并查集
_OP_CHEN24 分钟前
【算法基础篇】(四十五)裴蜀定理与扩展欧几里得算法:从不定方程到数论万能钥匙
算法·蓝桥杯·数论·算法竞赛·裴蜀定理·扩展欧几里得算法·acm/icpc
shangjian00734 分钟前
AI大模型-机器学习-算法-线性回归
人工智能·算法·机器学习
2301_800256111 小时前
B+树:数据库的基石 R树:空间数据的索引专家 四叉树:空间划分的网格大师
数据结构·数据库·b树·机器学习·postgresql·r-tree
mjhcsp1 小时前
C++ KMP 算法:原理、实现与应用全解析
java·c++·算法·kmp
lizhongxuan1 小时前
Manus: 上下文工程的最佳实践
算法·架构