排序八卦炉之冒泡、快排【完整版】

文章目录

  • 1.冒泡排序
    • 1.1代码实现
    • 1.2复杂度
  • 2.快速排序
    • 2.1人物及思想介绍【源于百度】
    • 2.2hoare【霍尔】版本
      • 1.初识代码
      • 2.代码分析
      • 3.思其因果
    • 2.3挖坑版本
      • 1.初始代码
      • 2.代码分析
      • 3.思想比较
    • 2.4指针版本
      • 1.初识代码
      • 2.代码分析
      • 3.问题探讨
    • 2.5集体优化
    • 2.6极致优化
    • 2.7非递归版本
      • 1.初识代码
      • 2.代码分析
    • 2.8相关博客及完整代码

在这里插入图片描述

1.冒泡排序

在这里插入图片描述

1.1代码实现

//插入排序  O(N)~O(N^2)
//冒泡排序  O(N)~O(N^2)
//当数据有序 二者均为O(N)
//当数据接近有序或局部有序 插排更优
void BubbleSort(int* a, int n)
{
	assert(a);
	int flag = 1;
	for (int i = 0; flag && i < n - 1; ++i)
	{
		flag = 0;
		for (int j = 0; j < n - 1 - i; ++j)
		{
			if (a[j] > a[j + 1])
			{
				Swap(&a[j + 1], &a[j]);
				flag = 1;
			}
		}
	}
}

1.2复杂度

  1. 最坏:
    比较n-1轮
    每一轮比较次数:n n-1 n-2 n-3 … 1 ≈ N^2
  2. 最优:
    比较n-1轮
    数据有序–每一轮只判断不比较 – N

2.快速排序

2.1人物及思想介绍【源于百度】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2hoare【霍尔】版本

1.初识代码

//霍尔版本
int PartSort1(int* a, int begin, int end)
{

	int left = begin, right = end, x = left;
	while (left < right)
	{
		//右找小
		while (left < right && a[right] >= a[x])
			--right;

		//左找大
		while (left < right && a[left] <= a[x])
			++left;

		Swap(&a[left], &a[right]);
	}

	Swap(&a[x], &a[left]);
	x = left;

	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort1(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.思其因果

Q:为什么a[x]【作为基准值key】置于左侧 – 右边先移动?
A:目的是为了保证相遇位置的值<=key 从而把key与相遇值交换 不打乱“左放小,右放大”的思想
在这里插入图片描述

2.3挖坑版本

1.初始代码

//挖坑版本
int PartSort2(int* a, int begin, int end)
{
	int x = begin, key = a[begin];

    while (begin < end)
	{
		while (begin < end && a[end] >= key)
			--end;
		a[x] = a[end];
		x = end;


		while (begin < end && a[begin] <= key)
			++begin;
		a[x] = a[begin];
		x = begin;
	}

	a[x] = key;
	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort1(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.思想比较

霍尔版本:右找小 左找打 大小交换 依次递归
挖坑版本:记录key值 x位–置空 右找小入坑 坑位更新 左找大入坑 坑位更新 依次递归

在这里插入图片描述

2.4指针版本

1.初识代码

int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	
	int prv = begin, cp = begin + 1, x = begin;

	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);

		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	
	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort3(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.问题探讨

在这里插入图片描述

2.5集体优化

//快速排序   O(N * logN)
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;

	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] < a[end])
			return end;
		else
			return begin;
	}
	else //a[begin] >= a[mid]
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{
	int left = begin, right = end, x = left;

	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);

	while (left < right)
	{
		//右找小
		while (left < right && a[right] >= a[x])
			--right;

		//左找大
		while (left < right && a[left] <= a[x])
			++left;

		Swap(&a[left], &a[right]);
	}

	Swap(&a[x], &a[left]);
	x = left;

	return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{
	int x = begin;
	
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]); 
	int key = a[x];
    
	while (begin < end)
	{
		while (begin < end && a[end] >= key)
			--end;
		a[x] = a[end];
		x = end;


		while (begin < end && a[begin] <= key)
			++begin;
		a[x] = a[begin];
		x = begin;
	}

	a[x] = key;
	return x;
}  
//指针版本
int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	
	int prv = begin, cp = begin + 1, x = begin;
	
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);

	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);

		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	
	return x;
}
void QuickSort(int* a, int begin, int end)    
{
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort2(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

2.6极致优化

在这里插入图片描述

在这里插入图片描述

2.7非递归版本

递归版本存在的问题:若递归层次太深 导致栈溢出问题
递归改非递归的方法:

  1. 直接改循环 – 斐波那契数列、归并排序等
  2. 数据结构的栈(Stack)模拟递归【Stack的空间是从堆申请的 堆内存比栈内存大】

1.初识代码

int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	int prv = begin, cp = begin + 1, x = begin;
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);
	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);
		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	return x;
}
void QuickSort_NonRecursion(int* a, int begin, int end)
{
	ST st;
	StackInit(&st);

	StackPush(&st, begin);
	StackPush(&st, end);

	while (!StackEmpty(&st))
	{
		int right = StackTop(&st);
		StackPop(&st);
		int left = StackTop(&st);
		StackPop(&st);

		int x = PartSort3(a, left, right);
		 
		if (x + 1 < right)
		{
			StackPush(&st, x + 1);
			StackPush(&st, right);
		}
		// [left, x-1] x [x+1, right]
		if (left < x - 1)
		{
			StackPush(&st, left);
			StackPush(&st, x - 1);
		}
	}
	StackDestroy(&st);
}

2.代码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.8相关博客及完整代码

点击 [qsort与bubble之间不为人知的关系](htt p://t.csdn.cn/filuW) 查看博主之前关于分析这两个排序的博客。

//快速排序   O(N * logN)
int count = 0;  //测试递归次数
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;

	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] < a[end])
			return end;
		else
			return begin;
	}
	else //a[begin] >= a[mid]
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{
	int left = begin, right = end, x = left;

	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);

	while (left < right)
	{
		//右找小
		while (left < right && a[right] >= a[x])
			--right;

		//左找大
		while (left < right && a[left] <= a[x])
			++left;

		Swap(&a[left], &a[right]);
	}

	Swap(&a[x], &a[left]);
	x = left;

	return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{
	int x = begin;
	
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]); 
	int key = a[x];
    
	while (begin < end)
	{
		while (begin < end && a[end] >= key)
			--end;
		a[x] = a[end];
		x = end;


		while (begin < end && a[begin] <= key)
			++begin;
		a[x] = a[begin];
		x = begin;
	}

	a[x] = key;
	return x;
}  
//指针版本
int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointer
	int prv = begin, cp = begin + 1, x = begin;
	//确定更合适的key
	int mid_x = GetMid_X(a, begin, end);
	Swap(&a[x], &a[mid_x]);
	while (cp <= end)
	{
		if (a[cp] < a[x] && ++prv != cp)
			Swap(&a[prv], &a[cp]);
		++cp;
	}
	Swap(&a[prv], &a[x]);
	x = prv;
	return x;
}

void QuickSort(int* a, int begin, int end)
{
	count++;
	//begin:左区间左边界下标 
	//end  :右区间右边界下标
	//begin==end:数据量=1 无需排序 直接返回
	//begin>end :无效区间 无需排序 直接返回
	if (begin >= end)
		return;

	int x = PartSort3(a, begin, end);

	// [begin, x - 1] x [x + 1, end]
	QuickSort(a, begin, x - 1);
	QuickSort(a, x+1, end);
}

/*
void QuickSort(int* a, int begin, int end)
{
	count++;
	if (begin >= end)
		return;
	
	if (end - begin > 10)
	{
		int x = PartSort3(a, begin, end);
		
		// [begin, x-1] x [x+1, end]
		QuickSort(a, begin, x - 1);
		QuickSort(a, x + 1, end);
	}
	else 
		InsertSort(a + begin, end - begin + 1);
}
*/
//非递归版本
void QuickSort_NonRecursion(int* a, int begin, int end)
{
	ST st;
	StackInit(&st);

	StackPush(&st, begin);
	StackPush(&st, end);

	while (!StackEmpty(&st))
	{
		int end = StackTop(&st);
		StackPop(&st);
		int begin = StackTop(&st);
		StackPop(&st);

		int x = PartSort3(a, begin, end);
		 
		if (x + 1 < end)
		{
			StackPush(&st, x + 1);
			StackPush(&st, end);
		}
		// [begin, x-1] x [x+1, end]
		if (begin < x - 1)
		{
			StackPush(&st, begin);
			StackPush(&st, x - 1);
		}
	}
	StackDestroy(&st);
}

你可能感兴趣的:(深度学习数据结构,c语言,数据结构,排序算法,算法)