七大排序完整版

news2024/11/23 13:51:38

目录

一、直接插入排序

(一)单趟直接插入排

1.分析+核心代码 

2.完整代码

(二)全部直接插入排

1.分析+核心代码

2.完整代码

(三)时间复杂度和空间复杂度

二、希尔排序

(一)对一组数据进行直接插入排序

(二)对每个分组分别进行直接插入排序

(三)对每个分组同时进行直接插入排序

(四)可变的gap

(五)时间复杂度和空间复杂度

三、直接选择排序

(一)找一个最小值

1、单趟直接选择排序

2、多趟选择排序

3、时间复杂度和空间复杂度

(二)同时找最小值和最大值

1、单趟直接选择排序

2、多趟选择排序

3、时间复杂度和空间复杂度

四、冒泡排序

(一)核心代码

(二)完整代码

(三)时间复杂度

五、快速排序

(一)Hoare

1. 易出错分析——死循环

2. 易出错分析——越界

3. 一次快排核心代码

4. 递归核心代码

5. 测试代码

6. 时间复杂度

(二)挖坑法

1. 单趟挖坑的代码

2. 单趟测试代码

3. 递归挖坑代码

4. 递归挖坑测试代码

(三)前后指针

1. 单趟核心代码

2. 单趟测试代码

3. 递归核心代码

4. 递归测试代码

(四)非递归实现(栈)

六、归并排序

1. 递归核心代码

2. 测试代码

3. 非递归核心代码

4. 测试代码

七、堆排序

1. 向下调整

2. 建堆

3. 堆排序代码

4. 向上调整

5. 测试


一、直接插入排序

(一)单趟直接插入排

1.分析+核心代码 

void InsertSort(int* data, int n)
{
	//[0,end]有序
	int end = n - 2;
	int tmp = data[end+1];
	while (end >= 0)//升序
	{
		if (data[end] > tmp)
		{
			data[end + 1] = data[end];
			--end;
		}
		else
		{
			break;
		}
	}
	data[end + 1] = tmp;
}

2.完整代码

#define _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
void InsertSort(int* data, int n)
{
	//[0,end]有序
	int end = n - 2;
	int tmp = data[end+1];
	while (end >= 0)//升序
	{
		if (data[end] > tmp)
		{
			data[end + 1] = data[end];
			--end;
		}
		else
		{
			break;
		}
	}
	data[end + 1] = tmp;
}
void Print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
}
int main()
{
	int a[] = { 1,6,10,12,13,7 };
	InsertSort(a, sizeof(a) / sizeof(int));
	Print(a, sizeof(a) / sizeof(int));
	return 0;
}

(二)全部直接插入排

1.分析+核心代码

  • 红色线条前的数据依次和tmp比较,比tmp大就往后面挪动 

void InsertSort(int* data, int n)
{
	for (int i = 0; i < n-1; i++)
	{
		int end = i;
		int tmp = data[end+1];
		while (end >= 0)//升序
		{
			if (data[end] > tmp)
			{
				data[end + 1] = data[end];
				--end;
			}
			else
			{
				break;
			}
		}
		data[end + 1] = tmp;
	}
}

2.完整代码

#define _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
void InsertSort(int* data, int n)
{
	for (int i = 0; i < n-1; i++)
	{
		int end = i;
		int tmp = data[end+1];
		while (end >= 0)//升序
		{
			if (data[end] > tmp)
			{
				data[end + 1] = data[end];
				--end;
			}
			else
			{
				break;
			}
		}
		data[end + 1] = tmp;
	}
}
void Print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
}
int main()
{
	int a[] = { 1,6,17,12,4 };
	InsertSort(a, sizeof(a) / sizeof(int));
	Print(a, sizeof(a) / sizeof(int));
	return 0;
}

(三)时间复杂度和空间复杂度

二、希尔排序

(一)对一组数据进行直接插入排序

void ShellSort(int* data, int n)
{
	int gap = 3;
	for (int i = 0; i+gap < n; i+=gap)//对第一组数据进行插入排序
	{
		int end = i;
		int tmp = data[end + gap];
		while (end >= 0)
		{
			if (data[end] > tmp)
			{
				data[end + gap] = data[end];
				end = end - gap;
			}
			else
				break;
		}
		data[end + gap] = tmp;
	}
}
#define _CRT_SECURE_NO_WARNINGS  1

#include<stdio.h>
void ShellSort(int* data, int n)
{
	int gap = 3;
	for (int i = 0; i+gap < n; i+=gap)//对第一组数据进行插入排序
	{
		int end = i;
		int tmp = data[end + gap];
		while (end >= 0)
		{
			if (data[end] > tmp)
			{
				data[end + gap] = data[end];
				end = end - gap;
			}
			else
				break;
		}
		data[end + gap] = tmp;
	}
}
void Print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
int main()
{
	int a[] = { 9,4,3,0,5,6,7,2,1,8 };
	ShellSort(a, sizeof(a) / sizeof(int));
	Print(a, sizeof(a) / sizeof(int));
	return 0;
}

(二)对每个分组分别进行直接插入排序

void ShellSort(int* data, int n)
{
	int gap = 3;
	for (int k = 0; k < gap; k++)//一共有gap组
	{
		for (int i = k; i + gap < n; i += gap)//对第k组数据进行插入排序
		{
			int end = i;
			int tmp = data[end + gap];
			while (end >= 0)
			{
				if (data[end] > tmp)
				{
					data[end + gap] = data[end];
					end = end - gap;
				}
				else
					break;
			}
			data[end + gap] = tmp;
		}
	}
}
#define _CRT_SECURE_NO_WARNINGS  1

#include<stdio.h>
void ShellSort(int* data, int n)
{
	int gap = 3;
	for (int k = 0; k < gap; k++)//一共有gap组
	{
		for (int i = k; i + gap < n; i += gap)//对第k组数据进行插入排序
		{
			int end = i;
			int tmp = data[end + gap];
			while (end >= 0)
			{
				if (data[end] > tmp)
				{
					data[end + gap] = data[end];
					end = end - gap;
				}
				else
					break;
			}
			data[end + gap] = tmp;
		}
	}
}
void Print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
int main()
{
	int a[] = { 9,4,3,0,5,6,7,2,1,8 };
	ShellSort(a, sizeof(a) / sizeof(int));
	Print(a, sizeof(a) / sizeof(int));
	return 0;
}

(三)对每个分组同时进行直接插入排序

void ShellSort(int* data, int n)
{
	int gap = 3;

	for (int i = 0; i + gap < n; i++)//对多组同时进行直接插入排序
	{
		int end = i;
		int tmp = data[end + gap];
		while (end >= 0)
		{
			if (data[end] > tmp)
			{
				data[end + gap] = data[end];
				end = end - gap;
			}
			else
				break;
		}
		data[end + gap] = tmp;
	}	
}
#define _CRT_SECURE_NO_WARNINGS  1

#include<stdio.h>
void ShellSort(int* data, int n)
{
	int gap = 3;
	for (int i = 0; i + gap < n; i++)//对多组同时进行直接插入排序
	{
		int end = i;
		int tmp = data[end + gap];
		while (end >= 0)
		{
			if (data[end] > tmp)
			{
				data[end + gap] = data[end];
				end = end - gap;
			}
			else
				break;
		}
		data[end + gap] = tmp;
	}	
}
void Print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
int main()
{
	int a[] = { 9,4,3,0,5,6,7,2,1,8 };
	ShellSort(a, sizeof(a) / sizeof(int));
	Print(a, sizeof(a) / sizeof(int));
	return 0;
}

(四)可变的gap

void ShellSort(int* data, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//1、gap > 1  与排序
		//2、gap == 1直接插入排序
		gap = gap / 3 + 1;

		for (int i = 0; i + gap < n; i++)//对多组同时进行直接插入排序
		{
			int end = i;
			int tmp = data[end + gap];
			while (end >= 0)
			{
				if (data[end] > tmp)
				{
					data[end + gap] = data[end];
					end = end - gap;
				}
				else
					break;
			}
			data[end + gap] = tmp;
		}
	}	
}
#define _CRT_SECURE_NO_WARNINGS  1

#include<stdio.h>
void ShellSort(int* data, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//1、gap > 1  与排序
		//2、gap == 1直接插入排序
		gap = gap / 3 + 1;

		for (int i = 0; i + gap < n; i++)//对多组同时进行直接插入排序
		{
			int end = i;
			int tmp = data[end + gap];
			while (end >= 0)
			{
				if (data[end] > tmp)
				{
					data[end + gap] = data[end];
					end = end - gap;
				}
				else
					break;
			}
			data[end + gap] = tmp;
		}
	}	
}
void Print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
int main()
{
	int a[] = { 9,4,3,0,5,6,7,2,1,8 };
	ShellSort(a, sizeof(a) / sizeof(int));
	Print(a, sizeof(a) / sizeof(int));
	return 0;
}

(五)时间复杂度和空间复杂度

三、直接选择排序

  • 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

(一)找一个最小值

1、单趟直接选择排序

  • 从待排序列中选出一个最小值,然后放在序列的起始位置
void SelectSort(int* data, int n)
{
	int start = 0;//待排序的数据的区间的开始位置
	int min_index = start;//最小元素的小标
	for (int i = start; i < n; i++)
	{
		if (data[i] < data[min_index])
		{
			min_index = i;
		}
	}
	Swap(&data[start], &data[min_index]); //最小值与第一个元素交换位置
}
#define _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
void SelectSort(int* data, int n)
{
	int start = 0;//待排序的数据的区间的开始位置
	int min_index = start;//最小元素的下标
	for (int i = start; i < n; i++)
	{
		if (data[i] < data[min_index])
		{
			min_index = i;
		}
	}
	Swap(&data[start], &data[min_index]); //最小值与第一个元素交换位置
}
int main()
{
	int a[] = { 9,3,6,2,7,4 };
	print(a, sizeof(a) / sizeof(int));
	SelectSort(a, sizeof(a) / sizeof(int));
	print(a, sizeof(a) / sizeof(int));

	return 0;
}

2、多趟选择排序

void SelectSort(int* data, int n)
{
	for (int k = 0; k < n; k++)//某一趟选择排序从下标为k的元素开始
	{
		int start = k;//待排序的数据的区间的开始位置
		int min_index = start;//最小元素的下标
		for (int i = start; i < n; i++)
		{
			if (data[i] < data[min_index])
			{
				min_index = i;
			}
		}
		Swap(&data[start], &data[min_index]); //最小值与参与第一个元素交换位置
	}
}

3、时间复杂度和空间复杂度

(二)同时找最小值和最大值

1、单趟直接选择排序

  • 一趟选出两个值,一个最大值一个最小值,分别放在放在开头和结尾
void SelectSort(int* data, int n)
{

	int begin = 0;//待排序的数据的区间的开始位置
	int end = n - 1;
	int min_index = begin;//最小元素的下标
	int max_index = end;//最大元素的下标
	for (int i = 0; i < n; i++)
	{
		if (data[i] < data[min_index])
		{
			min_index = i;
		}

		if (data[i] > data[max_index])
		{
			max_index = i;
		}
	}
	Swap(&data[begin], &data[min_index]); //最小值与第一个元素交换位置

	if (max_index == begin)//如果最大值在第一个位置处
	{
		max_index = min_index;
	}

	Swap(&data[end], &data[max_index]); //最大值和最后一个元素交换位置

	//下次调整[1,n-2]之间的数据
}

2、多趟选择排序

void SelectSort(int* data, int n)
{

	int begin = 0;//待排序的数据的区间的开始位置
	int end = n - 1;
	while (begin < end)
	{
		int min_index = begin;//最小元素的下标
		int max_index = end;//最大元素的下标
		for (int i = begin; i <= end; i++)
		{
			if (data[i] < data[min_index])
			{
				min_index = i;
			}

			if (data[i] > data[max_index])
			{
				max_index = i;
			}
		}
		Swap(&data[begin], &data[min_index]); //最小值与第一个元素交换位置

		if (max_index == begin)//如果最大值在第一个位置处
		{
			max_index = min_index;
		}

		Swap(&data[end], &data[max_index]); //最大值和最后一个元素交换位置

		//下次调整[1,n-2]之间的数据
		begin++;
		end--;
	}	
}
#define _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
void SelectSort(int* data, int n)
{

	int begin = 0;//待排序的数据的区间的开始位置
	int end = n - 1;
	while (begin < end)
	{
		int min_index = begin;//最小元素的下标
		int max_index = end;//最大元素的下标
		for (int i = begin; i <= end; i++)
		{
			if (data[i] < data[min_index])
			{
				min_index = i;
			}

			if (data[i] > data[max_index])
			{
				max_index = i;
			}
		}
		Swap(&data[begin], &data[min_index]); //最小值与第一个元素交换位置

		if (max_index == begin)//如果最大值在第一个位置处
		{
			max_index = min_index;
		}

		Swap(&data[end], &data[max_index]); //最大值和最后一个元素交换位置

		//下次调整[1,n-2]之间的数据
		begin++;
		end--;
	}	
}
int main()
{
	int a[] = { 9,3,6,2,7,4 };
	print(a, sizeof(a) / sizeof(int));
	SelectSort(a, sizeof(a) / sizeof(int));
	print(a, sizeof(a) / sizeof(int));

	return 0;
}

3、时间复杂度和空间复杂度

四、冒泡排序

  • 基本思想:从第一个元素开始,比较相邻元素的大小,若大小有误,则对调再进行下一个元素的比较,如此扫过依次之后就可以确保最后一个元素位于正确的顺序。接着进行第二次扫描

(一)核心代码

void BubbleSort(int* data, int n)
{
	for (int end = n - 1; end >= 0; end--)//每次将数据交换到下标为end的位置处
	{
		bool exchange = false;
		for (int i = 0; i < end; i++)//[i,end-1]
		{
			if (data[i] > data[i + 1])
			{
				Swap(&data[i], &data[i + 1]);
				exchange = true;
			}
		}

		if (exchange == false)
			break;
	}
}

(二)完整代码

#include<stdio.h>
#include<stdbool.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
void BubbleSort(int* data, int n)
{
	for (int end = n - 1; end >= 0; end--)//每次将数据交换到下标为end的位置处
	{
		bool exchange = false;
		for (int i = 0; i < end; i++)//[i,end-1]
		{
			if (data[i] > data[i + 1])
			{
				Swap(&data[i], &data[i + 1]);
				exchange = true;
			}
		}

		if (exchange == false)
			break;
	}
}
int main()
{
	int a[] = { 9,3,6,2,7,4 };
	//int a[] = { 1,2,3,4,5,6 };
	print(a, sizeof(a) / sizeof(int));
	BubbleSort(a, sizeof(a) / sizeof(int));
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

(三)时间复杂度

五、快速排序

(一)Hoare

1. 易出错分析——死循环

2. 易出错分析——越界

3. 一次快排核心代码

int PartSort(int* data, int begin, int end)
{
	int key_index = begin;
	int left = begin;
	int right = end;
	while (left < right)
	{
		//右边先走
		while (left < right && data[right] >= data[key_index])//右边找小
		{
			--right;
		}
		while (left < right && data[left] <= data[key_index])//左边找大
		{
			++left;
		}

		Swap(&data[left], &data[right]);
	}
	Swap(&data[key_index], &data[left]);
	return left;//返回相遇点,key的当前下标
}

4. 递归核心代码

void QuickSort(int* data, int begin, int end)
{
	if (begin >= end)//当只有一个数据或是数组不存在时,不需要进行操作
		return;

	int key_index = begin;
	int left = begin;
	int right = end;
	while (left < right)
	{
		//右边先走
		while (left < right && data[right] >= data[key_index])//右边找小
		{
			--right;
		}
		while (left < right && data[left] <= data[key_index])//左边找大
		{
			++left;
		}

		Swap(&data[left], &data[right]);
	}
	//此时left=right
	Swap(&data[key_index], &data[left]);
	QuickSort(data, begin, left - 1);//左区间
	QuickSort(data, left+1,end);//右区间
}

5. 测试代码

#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void QuickSort(int* data, int begin, int end)
{
	if (begin >= end)//当只有一个数据或是数组不存在时,不需要进行操作
		return;

	int key_index = begin;
	int left = begin;
	int right = end;
	while (left < right)
	{
		//右边先走
		while (left < right && data[right] >= data[key_index])//右边找小
		{
			--right;
		}
		while (left < right && data[left] <= data[key_index])//左边找大
		{
			++left;
		}

		Swap(&data[left], &data[right]);
	}
	//此时left=right
	Swap(&data[key_index], &data[left]);
	QuickSort(data, begin, left - 1);//左区间
	QuickSort(data, left+1,end);//右区间
}
int main()
{
	//int a[] = {6,1,2,7,9,3,4,5,10,8 };
	int a[] = {6,1,2,7,9,3,4,5,10,8 };

	print(a, sizeof(a) / sizeof(int));
	QuickSort(a, 0,sizeof(a) / sizeof(int)-1);
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

6. 时间复杂度

(二)挖坑法

1. 单趟挖坑的代码

int PartSort(int* data, int left, int right)
{
	int key = data[left];
	int hole = left;//最左边坑所在的下标
	while (left < right)
	{
		while (left<right && data[right]>=key)//右边找小
		{
			--right;
		}
		data[hole] = data[right];//填坑
		hole = right;//更新坑位

		while (left < right && data[left] <= key)//左边找大
		{
			++left;
		}
		data[hole] = data[left];
		hole = left;//更新坑位
	}

	data[hole] = key;
	return hole;//返回此时key的下标
}

2. 单趟测试代码

#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

int PartSort(int* data, int left, int right)
{
	int key = data[left];
	int hole = left;//最左边坑所在的下标
	while (left < right)
	{
		while (left < right && data[right] >= key)//右边找小
		{
			--right;
		}
		data[hole] = data[right];//填坑
		hole = right;//更新坑位

		while (left < right && data[left] <= key)//左边找大
		{
			++left;
		}
		data[hole] = data[left];
		hole = left;//更新坑位
	}

	data[hole] = key;
	return hole;//返回此时key的下标
}
int main()
{
	//int a[] = {6,1,2,7,9,3,4,5,10,8 };
	int a[] = { 6,1,2,7,9,3,4,5,10,8 };

	print(a, sizeof(a) / sizeof(int));
	int x =PartSort(a, 0, sizeof(a) / sizeof(int) - 1);
	printf("%d\n", x);
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

3. 递归挖坑代码

void QuickSort(int* data, int begin, int end)
{
	if (begin >= end)
		return;

	int left = begin;
	int right = end;
	int key = data[left];
	int hole = left;//最左边坑所在的下标
	while (left < right)
	{
		while (left < right && data[right] >= key)//右边找小
		{
			--right;
		}
		data[hole] = data[right];//填坑
		hole = right;//更新坑位

		while (left < right && data[left] <= key)//左边找大
		{
			++left;
		}
		data[hole] = data[left];
		hole = left;//更新坑位
	}

	data[hole] = key;
	
	QuickSort(data, begin, hole - 1);//递归左边
	QuickSort(data, hole +1,end);//递归右边
}

4. 递归挖坑测试代码

#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void QuickSort(int* data, int begin, int end)
{
	if (begin >= end)
		return;

	int left = begin;
	int right = end;
	int key = data[left];
	int hole = left;//最左边坑所在的下标
	while (left < right)
	{
		while (left < right && data[right] >= key)//右边找小
		{
			--right;
		}
		data[hole] = data[right];//填坑
		hole = right;//更新坑位

		while (left < right && data[left] <= key)//左边找大
		{
			++left;
		}
		data[hole] = data[left];
		hole = left;//更新坑位
	}

	data[hole] = key;
	
	QuickSort(data, begin, hole - 1);//递归左边
	QuickSort(data, hole +1,end);//递归右边
}
int main()
{
	//int a[] = {6,1,2,7,9,3,4,5,10,8 };
	int a[] = { 6,1,2,7,9,3,4,5,10,8 };

	print(a, sizeof(a) / sizeof(int));
	QuickSort(a, 0, sizeof(a) / sizeof(int) - 1);
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

(三)前后指针

  • 最开始prev和cur相邻
  • 当cur遇到比key大的值后,他们之间的值都是比key大的值
  • 当cur找小,找到小的以后与++prev位置的值交换,相当于把大的值翻滚式向右边推,同时把小的换到左边 

1. 单趟核心代码

int PartSort(int* data, int left, int right)
{
	int prev = left;
	int cur = left + 1;
	int key_index = left;

	while (cur <= right)
	{
		if (data[cur] < data[key_index] && ++prev != cur)//如果prev和cur指向同一个数据没必要交换
		{
			Swap(&data[cur], &data[prev]);
		}
		++cur;
	}

	Swap(&data[key_index], &data[prev]);
	key_index = prev;
	return key_index;
}

2. 单趟测试代码

#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

int PartSort(int* data, int left, int right)
{
	int prev = left;
	int cur = left + 1;
	int key_index = left;

	while (cur <= right)
	{
		if (data[cur] < data[key_index] && ++prev != cur)//如果prev和cur指向同一个数据没必要交换
		{
			Swap(&data[cur], &data[prev]);
		}
		++cur;
	}

	Swap(&data[key_index], &data[prev]);
	key_index = prev;
	return key_index;
}
int main()
{
	//int a[] = {6,1,2,7,9,3,4,5,10,8 };
	int a[] = { 6,1,2,7,9,3,4,5,10,8 };

	print(a, sizeof(a) / sizeof(int));
	int x = PartSort(a, 0, sizeof(a) / sizeof(int) - 1);
	printf("%d\n", x);
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

3. 递归核心代码

void QuickSort(int* data, int begin, int end)
{
	if (begin >= end)
		return;//结束条件

	int prev = begin;
	int cur = begin + 1;
	int key_index = begin;

	while (cur <= end)
	{
		if (data[cur] < data[key_index] && ++prev != cur)//如果prev和cur指向同一个数据没必要交换
		{
			Swap(&data[cur], &data[prev]);
		}
		++cur;
	}

	Swap(&data[key_index], &data[prev]);
	key_index = prev;//cur越界时,prev的位置
	
	QuickSort(data, begin, key_index-1);//递归排序左边
	QuickSort(data, key_index+1, end);//递归排序右边
}

4. 递归测试代码

#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void QuickSort(int* data, int begin, int end)
{
	if (begin >= end)
		return;//结束条件

	int prev = begin;
	int cur = begin + 1;
	int key_index = begin;

	while (cur <= end)
	{
		if (data[cur] < data[key_index] && ++prev != cur)//如果prev和cur指向同一个数据没必要交换
		{
			Swap(&data[cur], &data[prev]);
		}
		++cur;
	}

	Swap(&data[key_index], &data[prev]);
	key_index = prev;//cur越界时,prev的位置
	
	QuickSort(data, begin, key_index-1);//递归排序左边
	QuickSort(data, key_index+1, end);//递归排序右边
}
int main()
{
	//int a[] = {6,1,2,7,9,3,4,5,10,8 };
	int a[] = { 6,1,2,7,9,3,4,5,10,8 };

	print(a, sizeof(a) / sizeof(int));
	QuickSort(a, 0, sizeof(a) / sizeof(int) - 1);
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

(四)非递归实现(栈)

 

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << data[i]<<" ";
	}
	cout << endl;
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
int PartSort(int* data, int begin, int end)
{
	int key_index = begin;
	int left = begin;
	int right = end;
	while (left < right)
	{
		//右边先走
		while (left < right && data[right] >= data[key_index])//右边找小
		{
			--right;
		}
		while (left < right && data[left] <= data[key_index])//左边找大
		{
			++left;
		}

		Swap(&data[left], &data[right]);
	}
	Swap(&data[key_index], &data[left]);
	return left;//返回相遇点,key的当前下标
}

void QuickSort(int* data, int begin, int end)
{
	stack<int>s;
	s.push(begin);
	s.push(end);
	while (!s.empty())
	{
		int right = s.top();
		s.pop();

		int left = s.top();
		s.pop();

		int key_index = PartSort(data, left, right);//一趟快排以后key新的下标
		//[left,key_index-1]   key_index   [key_index+1,right]
		if (key_index+1 < right)//右区间合理则先入栈
		{
			s.push(key_index + 1);
			s.push(right);
		}

		if (left < key_index - 1)//左区间入栈
		{
			s.push(left);
			s.push(key_index - 1);
		}

	}
}
int main()
{
	//int a[] = {6,1,2,7,9,3,4,5,10,8 };
	int a[] = { 6,1,2,7,9,3,4,5,10,8 };
	print(a, sizeof(a) / sizeof(int));
	QuickSort(a, 0, sizeof(a) / sizeof(int) - 1);
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

六、归并排序

 

1. 递归核心代码

void _MergeSort(int* data, int left, int right, int* tmp)
{
	if (left == right)//当只有一个数据的时候不再分解
		return;//结束条件

	int mid = (left+right)/2;
	//[left,mid]   [mid+1,right]

	_MergeSort(data, left, mid, tmp);
	_MergeSort(data, mid + 1, right, tmp);

	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;

	int k = left;//每一个回合都从下标为left位置处在tmp中存放数据
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (data[begin1] <= data[begin2])
		{
			tmp[k++] = data[begin1++];
		}
		else
		{
			tmp[k++] = data[begin2++];
		}
	}

	while (begin1 <= end1)
	{
		tmp[k++] = data[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[k++] = data[begin2++];
	}

	memcpy(data + left, tmp + left, sizeof(int) * (right - left+1));
}

2. 测试代码

#include<stdio.h>
#include<malloc.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ",data[i]);
	}
	printf("\n");
}

void _MergeSort(int* data, int left, int right, int* tmp)
{
	if (left == right)//当只有一个数据的时候不再分解
		return;//结束条件

	int mid = (left+right)/2;
	//[left,mid]   [mid+1,right]

	_MergeSort(data, left, mid, tmp);
	_MergeSort(data, mid + 1, right, tmp);

	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;

	int k = left;//每一个回合都从下标为left位置处在tmp中存放数据
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (data[begin1] <= data[begin2])
		{
			tmp[k++] = data[begin1++];
		}
		else
		{
			tmp[k++] = data[begin2++];
		}
	}

	while (begin1 <= end1)
	{
		tmp[k++] = data[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[k++] = data[begin2++];
	}

	memcpy(data + left, tmp + left, sizeof(int) * (right - left+1));
}

void MergeSort(int* data, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	_MergeSort(data, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
}

int main()
{
	int a[] = {10,6,7,1,3,9,4,2};
	print(a, sizeof(a) / sizeof(int));
	MergeSort(a,  sizeof(a) / sizeof(int) );
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

3. 非递归核心代码

void _MergeSort(int* data, int* tmp,int begin1,int end1,int begin2,int end2)
{
	int j = begin1;
	int k = begin1;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (data[begin1]<=data[begin2])
		{
			tmp[k++] = data[begin1++];
		}
		else
		{
			tmp[k++] = data[begin2++];
		}
	}

	while (begin1 <= end1)
	{
		tmp[k++] = data[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[k++] = data[begin2++];
	}

	for (j; j <= end2; j++)//一个一个拷贝
	{
		data[j] = tmp[j];
	}
	//等价形式
	//memcpy(data+j, tmp+j, sizeof(int) * (end2 - j)+1);//左闭右闭

}

void MergeSort(int* data, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	
	int gap = 1;
	while (gap < n)
	{
		
		for (int i = 0; i < n; i += 2*gap)//i+2gap是下一组begin1的起始下标
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = begin2 + gap - 1;
			if (end1 >= n || begin2 >= n)//最后一组数据的第一个区间的后半部分不存在或者第二个区间整个不存在,都不需要进行合并
			{
				break;//意味着不需要进行_MergeSort,不用进行合并操作
			}

			if (end2 >= n)
			{
				end2 = n - 1;//最后一组数据的第2个区间的后半部分超出了
			}
			_MergeSort(data, tmp, begin1, end1, begin2, end2);
		}
		gap = gap * 2;
	}

	free(tmp);
	tmp = NULL;
}

4. 测试代码

#include<stdio.h>
#include<malloc.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ",data[i]);
	}
	printf("\n");
}

void _MergeSort(int* data, int* tmp,int begin1,int end1,int begin2,int end2)
{
	int j = begin1;
	int k = begin1;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (data[begin1]<=data[begin2])
		{
			tmp[k++] = data[begin1++];
		}
		else
		{
			tmp[k++] = data[begin2++];
		}
	}

	while (begin1 <= end1)
	{
		tmp[k++] = data[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[k++] = data[begin2++];
	}

	for (j; j <= end2; j++)//一个一个拷贝
	{
		data[j] = tmp[j];
	}
	//等价形式
	//memcpy(data+j, tmp+j, sizeof(int) * (end2 - j)+1);//左闭右闭

}

void MergeSort(int* data, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	
	int gap = 1;
	while (gap < n)
	{
		
		for (int i = 0; i < n; i += 2*gap)//i+2gap是下一组begin1的起始下标
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = begin2 + gap - 1;
			if (end1 >= n || begin2 >= n)//最后一组数据的第一个区间的后半部分不存在或者第二个区间整个不存在,都不需要进行合并
			{
				break;//意味着不需要进行_MergeSort,不用进行合并操作
			}

			if (end2 >= n)
			{
				end2 = n - 1;//最后一组数据的第2个区间的后半部分超出了
			}
			_MergeSort(data, tmp, begin1, end1, begin2, end2);
		}
		gap = gap * 2;
	}

	free(tmp);
	tmp = NULL;
}

int main()
{
	int a[] = {10,6,7,1,3,9,4,2,5};
	print(a, sizeof(a) / sizeof(int));
	MergeSort(a,  sizeof(a) / sizeof(int) );
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

七、堆排序

1. 向下调整

void AdjustDown(int* data,int n, int parent)//向下调整
{
	int child = 2 * parent + 1;//先假设左孩子结点的值最小
	
	while (child < n)
	{
		if (child+1<n && data[child+1] < data[child])
		{
			++child;
		}

		if (data[child] < data[parent])//排升序
		{
			Swap(&data[child], &data[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else//已成堆
			break;
	}
	
}

2. 建堆

void CreateHeap(int* data, int n)
{
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(data, n, i);
	}
}
#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void AdjustDown(int* data, int n, int parent)//向下调整
{
	int child = 2 * parent + 1;//先假设左孩子结点的值最小

	while (child < n)
	{
		if (child + 1 < n && data[child + 1] < data[child])
		{
			++child;
		}

		if (data[child] < data[parent])//排升序
		{
			Swap(&data[child], &data[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else//已成堆
			break;
	}

}

void CreateHeap(int* data, int n)
{
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(data, n, i);
	}
}
int main()
{
	int a[] = { 2,7,4,6,3,8,1 };
	print(a, sizeof(a) / sizeof(int));
	CreateHeap(a, sizeof(a) / sizeof(int));
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

3. 堆排序代码

void HeapSort(int* data, int n)
{
	//建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(data, n, i);//建小根堆
	}
	
	//排降序
	for (int i = 0; i < n; i++)
	{
		Swap(&data[0], &data[n - 1 - i]);//将堆顶元素和最后一个元素互换,再迭代向下调整
		AdjustDown(data, n - 1- i, 0);//n-1-i是重新建堆的数据个数
	}
}
#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void AdjustDown(int* data, int n, int parent)//向下调整
{
	int child = 2 * parent + 1;//先假设左孩子结点的值最小

	while (child < n)
	{
		if (child + 1 < n && data[child + 1] < data[child])
		{
			++child;
		}

		if (data[child] < data[parent])//排升序
		{
			Swap(&data[child], &data[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else//已成堆
			break;
	}

}

void HeapSort(int* data, int n)
{
	//建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(data, n, i);//建小根堆
	}
	
	//调整
	for (int i = 0; i < n; i++)
	{
		Swap(&data[0], &data[n - 1 - i]);//将堆顶元素和最后一个元素互换,再迭代向下调整
		AdjustDown(data, n - 1- i, 0);//n-1-i是重新建堆的数据个数
	}
}
int main()
{
	int a[] = { 2,7,4,6,3,8,1 };
	print(a, sizeof(a) / sizeof(int));
	HeapSort(a, sizeof(a) / sizeof(int));
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

4. 向上调整

void AdjustUp(int* data, int n, int child)//向上调整
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (data[child] < data[parent])
		{
			Swap(&data[child], &data[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}

5. 测试

#include<stdio.h>
void print(int* data, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", data[i]);
	}
	printf("\n");
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void AdjustUp(int* data, int n, int child)//向上调整
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (data[child] < data[parent])
		{
			Swap(&data[child], &data[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}

void CreateHeap(int* data, int n)
{
	//建堆
	for (int i = n - 1; i >= 0; --i)
	{
		AdjustUp(data, n, i);//建小根堆
	}
}
int main()
{
	int a[] = { 2,7,4,6,3,8,1 };
	print(a, sizeof(a) / sizeof(int));
	CreateHeap(a, sizeof(a) / sizeof(int));
	print(a, sizeof(a) / sizeof(int));
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/950250.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

畅捷通T+用户中locked勒索病毒后该怎么办?勒索病毒解密数据恢复

Locked勒索病毒是一种近年来在全球范围内引起广泛关注的网络安全威胁程序。它是一种加密货币劫持病毒&#xff0c;专门用于加密用户的数据并要求其支付赎金。Locked勒索病毒通过攻击各种系统漏洞和网络薄弱环节&#xff0c;使用户计算机受到感染并被加密锁定时&#xff0c;无法…

Unity+讯飞星火大模型+Web api,实现二次元小姐姐AI聊天互动

1.简述 最近讯飞的星火大模型更新了2.0版本&#xff0c;增强了AI的语言生成能力。毕竟是国产大语言模型&#xff0c;我也尝试使用了一下星火大模型的应用广场&#xff0c;体验还是很不错的。应用广场提供了很多AI助手工具&#xff0c;也支持用户创建自己的AI助手&#xff0c;能…

算法基础第三章

算法基础第三章 1、dfs(深度搜索)1.1、 递归回溯1.2、递归剪枝&#xff08;剪枝就是判断接下来的递归都不会满足条件&#xff0c;直接回溯&#xff0c;不再继续往下无意义的递归&#xff09; 2、bfs(广度搜索)2.1、最优路径&#xff08;只适合于边权都相等的题&#xff09; 3、…

使用 Netty 实现群聊功能的步骤和注意事项

文章目录 前言声明功能说明实现步骤WebSocket 服务启动Channel 初始化HTTP 请求处理HTTP 页面内容WebSocket 请求处理 效果展示总结 前言 通过之前的文章介绍&#xff0c;我们可以深刻认识到Netty在网络编程领域的卓越表现和强大实力。这篇文章将介绍如何利用 Netty 框架开发一…

QT登陆注册界面练习

一、界面展示 二、主要功能界面代码 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QMainWindow(parent), ui(new Ui::Widget) {ui->setupUi(this);this->setFixedSize(540,410); //设置固定尺寸th…

【计算机组成 课程笔记】2.1 设计自己的计算机

课程链接&#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 2 - 1 - 201-设计自己的计算机&#xff08;14‘24’‘&#xff09;_哔哩哔哩_bilibili 什么是指令系统体系结构&#xff1f;这个问题其实非常简单&#xff0c;但要想解释清楚也没有那么容易。我们还是从一个小故事…

兄弟 Goland 咱能一次性将注释设置好不

大家好&#xff0c;我是阿兵云原生 工作中我们都只是写注释是一个好习惯&#xff0c;作为新生代的农名工&#xff0c;特别烦的就是别人不写注释&#xff0c;但是自己偏偏又不喜欢写注释&#x1f602;&#x1f602;&#x1f602; 对于 golang 的注释&#xff0c;我发现很多新朋…

攻防世界-What-is-this

原题 解题思路 解压后文件 没有后缀&#xff0c;不知道是什么文件。用notepad打开找不到flag。 尝试当成压缩包解压。 用stegsolve以打开图片1&#xff0c; 合成两张图片。

MySQL中的表与视图:解密数据库世界的基石

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

vue中axios请求篇

vue中如何发起请求? 利用axios来发起请求&#xff0c;但是前期需要配置 首先安装axios 可以使用npm、yarn等进行安装 npm安装方式 npm install axios -sava //在项目文件夹中打开cmd或者终端进行安装依赖 yarn安装方式 yarn add axios 引入axios。我一般是在src下创建一个u…

【C++】学习C++STL中的数组——vector

❤️前言 好久不见大家&#xff01;今天的这篇博客是关于我对于STL(C标准模板库)中的容器vector的学习和理解&#xff0c;希望大家能够喜欢。 正文 vector是STL中的一种序列容器&#xff0c;对应着数据结构中的顺序表&#xff0c;也可以说是数组。在我们正式学习了解vector之前…

spring boot 测试用例

依赖包 <dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.5.RELEASE</version><scope>compile</scope></dependency><dependency><groupId>ju…

Autoware.universe部署05:实车调试

文章目录 一、建图1.1 点云地图1.2 高精地图 二、参数配置三、传感器数据通信接口3.1 雷达点云3.2 图像3.3 IMU3.4 GNSS RTK 四、实车调试4.1 编写启动4.2 修改传感器外参4.3 修改车身参数4.4 实车调试 本文介绍了 Autoware.universe 在实车上的部署&#xff0c;本系列其他文章…

《Web安全基础》04. 文件上传漏洞

web 1&#xff1a;文件上传漏洞2&#xff1a;WAF 绕过2.1&#xff1a;数据溢出2.2&#xff1a;符号变异2.3&#xff1a;数据截断2.4&#xff1a;重复数据 本系列侧重方法论&#xff0c;各工具只是实现目标的载体。 命令与工具只做简单介绍&#xff0c;其使用另见《安全工具录》…

2023京东口腔护理赛道行业数据分析(京东销售数据分析)

近年来&#xff0c;口腔护理逐渐成为年轻人重视的健康领域&#xff0c;从口腔护理整体市场来看&#xff0c;牙膏和牙刷等基础口腔护理产品仍占据主导地位。不过&#xff0c;随着口腔护理市场逐步朝向精致化、专业化、多元化等方向发展&#xff0c;不少新兴口腔护理产品受到消费…

C++学习|CUDA内存管理代码实例

前言&#xff1a;之前介绍了CUDA入门知识&#xff0c;对CUDA编程有了一个基本了解&#xff0c;但是实际写起来还是遇到很多问题&#xff0c;例如cpp文件该怎么调用cuda文件、cpu和gpu之间内存数据怎么交换、如何编写.cu和.cuh文件之类的。本篇文章将会以一个实现向量相加的代码…

【数据结构】二叉数的存储与基本操作的实现

文章目录 &#x1f340;二叉树的存储&#x1f333;二叉树的基本操作&#x1f431;‍&#x1f464;二叉树的创建&#x1f431;‍&#x1f453;二叉树的遍历&#x1f3a1;前中后序遍历&#x1f4cc;前序遍历&#x1f4cc;中序遍历&#x1f4cc;后续遍历 &#x1f6eb;层序遍历&am…

什么是Python爬虫分布式架构,可能遇到哪些问题,如何解决

目录 什么是Python爬虫分布式架构 1. 调度中心&#xff08;Scheduler&#xff09;&#xff1a; 2. 爬虫节点&#xff08;Crawler Node&#xff09;&#xff1a; 3. 数据存储&#xff08;Data Storage&#xff09;&#xff1a; 4. 反爬虫处理&#xff08;Anti-Scraping&…

2023-08-30力扣每日一题

链接&#xff1a; 1654. 到家的最少跳跃次数 题意&#xff1a; 从0出发&#xff0c;到X的最少步数 它可以 往前 跳恰好 a 个位置&#xff08;即往右跳&#xff09;。它可以 往后 跳恰好 b 个位置&#xff08;即往左跳&#xff09;。它不能 连续 往后跳 2 次。它不能跳到任何…

2023新版医保目录明细(药品查询)

查询医保目录的主要目的是为了了解医保政策对于特定医疗服务、药品和医疗器械的覆盖范围和支付标准。大众可以通过查看医保目录可以确定哪些药品可以被医保支付以及报销的比例和限额&#xff1b;医药从业者可通过查看医保目录可以即使了解医保政策的变化&#xff0c;便于做出相…