C学习(数据结构)-->排序

news2024/12/23 2:04:00

目录

一、直接插入排序

 二、希尔排序

三、直接选择排序

四、快速排序

 1、取基准值

1)hoare找基准值​编辑

 2) 挖坑法找基准值​编辑

 3)快慢指针找基准值​编辑

 2、递归快速排序

3、非递归快速排序

​编辑

五、归并排序

​编辑

六、计数排序

七、堆排序

八、冒泡排序​编辑

九、总代码 

Sort.h

Sort.cpp

main.cpp


一、直接插入排序

将需要排序的序列分成两部分,一部分序列已经排好序的为有序序列而还未排序的为无序序列,没每一次排序都是从无序序列中拿取数据直接插入到有序序列当中

//数据互换
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

//直接插入排序
void InsertSort(int* arr, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;//有序数组长度
		int tmp = arr[end + 1];//从无序数组从拿取数据
        //直接插入
		while (end >= 0)
		{
			//arr[end] > arr[end + 1]
			if (arr[end] > tmp)//找比tmp小的数据
			{
				arr[end + 1] = arr[end];//比tmp大的数据往后移动一步
				end--;
			}
			else
			{
				break;
			}
		}
		//跳出while循环前end自减过,所以是 end + 1 
		arr[end + 1] = tmp;
	}
}

 二、希尔排序

直接插入排序的优化,通过将数组划分为数个小组,每个小组各自使用直接插入排序,然后再次细分小组,继续使用直接插入排序,直到每个小组的数据量为 1 时,排序结束

//希尔排序
void ShellSort(int* arr, int n)
{
	int gap = n;
	while (gap > 1)
	{
        //划分小组
		//有可能出现 gap == 0 的情况,所以要保证最后一次gap == 1
		gap = gap / 3 + 1;
		//每个小组的直接插入排序
		for (int i = 0; i < n - gap; i++)//每两个数间隔gap,所以 n - gap
		{
			int end = i;//n - gap - 1;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				//arr[end] > arr[end + 1]
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
				arr[end + gap] = tmp;
			}
		}
	}
}

三、直接选择排序

每次通过直接在无序数组内寻找最大最小值,进行排序

//直接选择排序
void SelectSort(int* arr, int n)
{
	int begin = 0;
	int end = n - 1;

	while (begin < end)
	{
		int min = begin, max = begin;
		//找最大最小值
		for (int i = begin + 1; i <= end; i++)
		{
			//最小值
			if (arr[i] < arr[min])
			{
				min = i;
			}
			//最大值
			if (arr[i] > arr[max])
			{
				max = i;
			}
		}
		//避免max和begin在同一个位置
		if (max == begin)
		{
			max = min;
		}
		Swap(&arr[min], &arr[begin++]);
		Swap(&arr[max], &arr[end--]);
	}
}

四、快速排序

在数组内取一个基准值,将比基准值小和大的值各自放在基准值的两边, 然后再在分好的两边各取一个基准值,重复操作,直到分的每个部分都只剩一个数据,排序结束

 1、取基准值

1)hoare找基准值

//hoare版本找基准值
int _HoareQuickSort(int* arr, int left, int right)
{
	int key = left;
	left++;

	while (left <= right)
	{
		//找比基准值小的值
		while (left <= right && arr[right] > arr[key])
		{
			right--;
		}
		//找比基准值大的值
		while (left <= right && arr[left] < arr[key])
		{
			left++;
		}

		//防止最后一次 left > right
		if (left <= right)
		{
			Swap(&arr[left++], &arr[right--]);
		}
	}

 2) 挖坑法找基准值

//挖坑法找基准值
int _PitQuickSort(int* arr, int left, int right)
{
	int hole = left;//坑
	int key = arr[hole];//基准值
	while (left < right)
	{
		//找比基准值小的值
		while (left < right && arr[right] >= key)
		{
			right--;
		}
		arr[hole] = arr[right];//将找到的值放入坑内
		hole = right;//记录坑的位置

		//找比基准值大的值
		while (left < right && arr[left] < key)
		{
			left++;
		}
		arr[hole] = arr[left];//将找到的值放入坑内
		hole = left;//记录坑的位置
	}

	arr[hole] = key;
	return hole;
}

 3)快慢指针找基准值

//lomuto前后指针找基准值
int _LomutoQuickSort(int* arr, int left, int right)
{
	int prev = left, pcur = left + 1;
	int key = left;

	while (pcur <= right)
	{
		//寻找比基准值小的值
		if (arr[pcur] < arr[key] && ++prev != pcur) 
		{
			Swap(&arr[pcur], &arr[prev]);
		}
		pcur++;
	}
	Swap(&arr[key], &arr[prev]);
	return prev;
}

 2、递归快速排序

//快速排序
void QuickSort(int* arr, int left,int right)
{
	if (left >= right)
	{
		return;
	}
	//找基准值
	int key = _PitQuickSort(arr, left, right);
	//左子序列
	QuickSort(arr, left, key - 1);
	//右子序列
	QuickSort(arr, key + 1, right);
}

3、非递归快速排序

需要使用栈,通过栈来模拟递归,栈详见C学习(数据结构)-->栈-CSDN博客

//非递归快速排序
//借用数据结构-栈
void StackQuickSort(int* arr, int left, int right)
{
	ST st;
	STInit(&st);
	StackPush(&st, right);
	StackPush(&st, left);

	while (!StackEmpty(&st))
	{
		//取左右栈顶
		int begin = StackTop(&st);
		StackPop(&st);
		int end = StackTop(&st);
		StackPop(&st);
		
		int prev = begin;
		int pcur = begin + 1;
		int key = begin;

		//双指针法找基准值
		while (pcur <= end)
		{
			if (arr[pcur] < arr[key] && ++prev != pcur)
			{
				Swap(&arr[prev], &arr[pcur]);
			}
			pcur++;
		}
		Swap(&arr[prev], &arr[key]);

		key = prev;
		//基准值划分左右区间:[begin,key-1],[key+1,end]
		if (key + 1 < end)
		{
			StackPush(&st, end);
			StackPush(&st, key + 1);
		}
		if (key - 1 > begin)
		{
			StackPush(&st, key - 1);
			StackPush(&st, begin);
		}
	}
	STDestroy(&st);
}

五、归并排序

通过递归,将一个无序数组分为两个长度相同或者相近的数组,然后在分好的数组再次各自分两个数组,反复操作,直到数组不能再分为止,此时递归开始返回,在返回前,将数组按数据从小到大两两合并,当递归结束时,排序完成。

//归并排序
void _MergeSort(int* arr, int left, int right, int* tmp)
{
	if (left >= right)
	{
		return;
	}

	int mid = (left + right) / 2;
	_MergeSort(arr, left, mid, tmp);
	_MergeSort(arr, mid + 1, right, tmp);

	//合并两个数组 [left,mid] [mid+1,right]
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int index = begin1;

	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] < arr[begin2])
		{
			tmp[index++] = arr[begin1++];
		}
		else
		{
			tmp[index++] = arr[begin2++];
		}
	}

	//上面的循环结束,是因为 begin1 || begin2  越界,将剩下未排序的数据继续排序
	while (begin1 <= end1)
	{
		tmp[index++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[index++] = arr[begin2++];
	}

	//排序完成,拷贝tmp到arr
	for (int i = left; i <= right; i++)
	{
		arr[i] = tmp[i];
	}
}

void MergeSort(int* arr, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
    //归并排序
	_MergeSort(arr, 0, n - 1, tmp);

	free(tmp);
	tmp = NULL;
}

六、计数排序

通过统建立新数组统计数据内的数据出现的次数来排序 

这样的统计有缺点,第一,如果原数组中最小值为1000,那么就会新申请的数组中,就会至少申请1000个以上的空间,又由于最小值为1000,那么下标前1000个空间就会用不上,会很大程度上浪费空间 。第二,如果遇到负整数等情况,数组也无法做统计,无法进行排序。

将排序优化, 不是以最大值作为最大下标,而是以 最大值和最小值的差值作为最大下标,

例:max = 1022,min = 1000,那么最大下标就为 max - min = 22

在统计中,不是原数组中的数据( arr[i] )作为下标,而是原数组中的数据减去最小值 ( arr[i]-min )

作为下标,那么最后将统计好的数组拷贝回去原数组时,是将下标加上原数组中数据的最小值

( i+min )拷贝进原数组中。

这样可以大程度地节省空间,且可以统计负整数等。

//计数排序
void ConunSort(int* arr, int n)
{
	int max = arr[0], min = arr[0];

	//找最大值和最小值的差值
	for (int i = 1; i < n; i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
		if (arr[i] < min)
		{
			min = arr[i];
		}
	}
	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
		perror("malloc fail!!!");
		exit(1);
	}

	//初始化数组
	memset(count, 0, range * sizeof(int));

	//统计数组每个数据出现的次数
	for (int i = 0; i < n; i++)
	{
		count[arr[i] - min]++;
	}
	//取count数据放入arr中
	int index = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			arr[index++] = i + min;
		}
	}
}

七、堆排序

具体看C学习(数据结构)--> 实现顺序结构二叉树-CSDN博客

//堆排序
//数据的向上调整(小堆)
void AdjustUpSmall(int* arr, int child)
{
	assert(arr);

	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//数据的向下调整(小堆)
void AdjustDownSmall(int* arr, int parent, int n)//n表示有效数据个数
{
	int child = parent * 2 + 1;//左孩子

	while (child < n)//如果左孩子在数组内
	{
		//比较左右孩子大小
		if (child + 1 < n && arr[child] > arr[child + 1])
		{
			child++;
		}
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//数据的向上调整(大堆)
void AdjustUpBig(int* arr, int child)
{
	assert(arr);

	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//数据的向下调整(大堆)
void AdjustDownBig(int* arr, int parent, int n)//n表示有效数据个数
{
	int child = parent * 2 + 1;//左孩子

	while (child < n)//如果左孩子在数组内
	{
		//比较左右孩子大小
		if (child + 1 < n && arr[child] < arr[child + 1])
		{
			child++;
		}
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


//堆排序
//排升序,建大堆
//排降序,建小堆

void HeapSortSmall(int* arr, int n)
{
	建小堆,向上排序法建堆
	//for (int i = 0; i < n; i++)
	//{
	//	AdjustUpSmall(arr, i);
	//}

	//建小堆,向下排序法建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDownSmall(arr, i, n);
	}

	//排降序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownSmall(arr, 0, end);
		end--;
	}
}

void HeapSortBig(int* arr, int n)
{
	//建大堆,向下排序法建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDownBig(arr, i, n);
	}

	//排升序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownBig(arr, 0, end);
		end--;
	}
}

八、冒泡排序

//冒泡排序
void BubbleSort(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		int exchange = 0;
		for (int j = 0; j < n - i - 1; j++)
		{
			if (arr[j] < arr[j + 1])
			{
				exchange = 1;
				Swap(&arr[j], &arr[j + 1]);
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

 九、其他

测试各个排序的运行效率

void test01()
{
	srand(time(0));
	int numsize = 50000;
	int begin = 0;
	int end = 0;

	int* a1 = (int*)malloc(sizeof(int) * numsize);
	int* a2 = (int*)malloc(sizeof(int) * numsize);
	int* a3 = (int*)malloc(sizeof(int) * numsize);
	int* a4 = (int*)malloc(sizeof(int) * numsize);
	int* a5 = (int*)malloc(sizeof(int) * numsize);
	int* a6 = (int*)malloc(sizeof(int) * numsize);
	int* a7 = (int*)malloc(sizeof(int) * numsize);
	int* a8 = (int*)malloc(sizeof(int) * numsize);
	int* a9 = (int*)malloc(sizeof(int) * numsize);
	
	for (int i = 0; i < numsize; i++)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
		a8[i] = a1[i];
		a9[i] = a1[i];
	}

	//冒泡排序
	begin = clock();
	BubbleSort(a1, numsize);
	end = clock();
	printf("冒泡排序:%d\n",end-begin);

	//堆排序
	begin = clock();
	HeapSortSmall(a2, numsize);
	end = clock();
	printf("堆排序:%d\n", end - begin);

	//直接插入排序
	begin = clock();
	InsertSort(a3, numsize);
	end = clock();
	printf("直接插入排序:%d\n", end - begin);

	//希尔排序
	begin = clock();
	ShellSort(a4, numsize);
	end = clock();
	printf("希尔排序:%d\n", end - begin);

	//直接选择排序
	begin = clock();
	SelectSort(a5, numsize);
	end = clock();
	printf("直接选择排序:%d\n", end - begin);

	//快速排序
	begin = clock();
	QuickSort(a6, 0, numsize - 1);
	end = clock();
	printf("快速排序:%d\n", end - begin);

	//非递归快速排序
	begin = clock();
	StackQuickSort(a7, 0, numsize - 1);
	end = clock();
	printf("非递归快速排序:%d\n", end - begin);

	//归并排序
	begin = clock();
	MergeSort(a8, numsize);
	end = clock();
	printf("归并排序:%d\n", end - begin);

	//计数排序
	begin = clock();
	ConunSort(a9, numsize);
	end = clock();
	printf("计数排序:%d\n", end - begin);

	free(a1);
	free(a2);
	free(a3);
	free(a4);
	free(a5);
	free(a6);
	free(a7);
	free(a8);
	free(a9);
	a1 = NULL;
	a2 = NULL;
	a3 = NULL;
	a4 = NULL;
	a5 = NULL;
	a6 = NULL;
	a7 = NULL;
	a8 = NULL;
	a9 = NULL;
}

int main()
{
	//测试
	test01();
	return 0;
}

运行结果

九、总代码 

Stack.h 和 Stack.cpp 详见C学习(数据结构)-->栈-CSDN博客

Sort.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
#include<memory.h>

//数据互换
void Swap(int* x, int* y);

//冒泡排序
void BubbleSort(int* arr, int n);

//数据的向上调整(小堆)
void AdjustUpSmall(int* arr, int child);

//数据的向下调整(小堆)
void AdjustDownSmall(int* arr, int parent, int n);

//数据的向上调整(大堆)
void AdjustUpBig(int* arr, int child);

//数据的向下调整(大堆)
void AdjustDownBig(int* arr, int parent, int n);

//堆排序
//排升序,建大堆
//排降序,建小堆
void HeapSortSmall(int* arr, int n);
void HeapSortBig(int* arr, int n);

//直接插入排序
void InsertSort(int* arr, int n);

//希尔排序
void ShellSort(int* arr, int n);

//直接选择排序
void SelectSort(int* arr, int n);

//快速排序
//hoare版本找基准值
int _HoareQuickSort(int* arr, int left, int right);
//挖坑法找基准值
int _PitQuickSort(int* arr, int left, int right);
//lomuto前后指针找基准值
int _LomutoQuickSort(int* arr, int left, int right);
//快速排序
void QuickSort(int* arr, int left, int right);
//非递归快速排序
//借用数据结构-栈
void StackQuickSort(int* arr, int left, int right);

//归并排序
void _MergeSort(int* arr, int left, int right, int* tmp);
void MergeSort(int* arr, int n);

//计数排序
void ConunSort(int* arr, int n);

Sort.cpp

#include"Sort.h"
#include"Stack.h"

//数据互换
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

//冒泡排序
void BubbleSort(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		int exchange = 0;
		for (int j = 0; j < n - i - 1; j++)
		{
			if (arr[j] < arr[j + 1])
			{
				exchange = 1;
				Swap(&arr[j], &arr[j + 1]);
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

//堆排序
//数据的向上调整(小堆)
void AdjustUpSmall(int* arr, int child)
{
	assert(arr);

	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//数据的向下调整(小堆)
void AdjustDownSmall(int* arr, int parent, int n)//n表示有效数据个数
{
	int child = parent * 2 + 1;//左孩子

	while (child < n)//如果左孩子在数组内
	{
		//比较左右孩子大小
		if (child + 1 < n && arr[child] > arr[child + 1])
		{
			child++;
		}
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//数据的向上调整(大堆)
void AdjustUpBig(int* arr, int child)
{
	assert(arr);

	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//数据的向下调整(大堆)
void AdjustDownBig(int* arr, int parent, int n)//n表示有效数据个数
{
	int child = parent * 2 + 1;//左孩子

	while (child < n)//如果左孩子在数组内
	{
		//比较左右孩子大小
		if (child + 1 < n && arr[child] < arr[child + 1])
		{
			child++;
		}
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


//堆排序
//排升序,建大堆
//排降序,建小堆

void HeapSortSmall(int* arr, int n)
{
	建小堆,向上排序法建堆
	//for (int i = 0; i < n; i++)
	//{
	//	AdjustUpSmall(arr, i);
	//}

	//建小堆,向下排序法建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDownSmall(arr, i, n);
	}

	//排降序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownSmall(arr, 0, end);
		end--;
	}
}

void HeapSortBig(int* arr, int n)
{
	//建大堆,向下排序法建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDownBig(arr, i, n);
	}

	//排升序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDownBig(arr, 0, end);
		end--;
	}
}

//直接插入排序
void InsertSort(int* arr, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int tmp = arr[end + 1];
		while (end >= 0)
		{
			//arr[end] > arr[end + 1]
			if (arr[end] > tmp)
			{
				arr[end + 1] = arr[end];
				end--;
			}
			else
			{
				break;
			}
		}
		//while循环中end自减,所以是 end + 1 
		arr[end + 1] = tmp;
	}
}

//希尔排序
void ShellSort(int* arr, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//有可能出现 gap == 0 的情况
		//要保证最后一次gap == 1;
		gap = gap / 3 + 1;
		//每个小组的直接选择插入
		for (int i = 0; i < n - gap; i++)//每两个数间隔gap,所以 n - gap
		{
			int end = i;//n - gap - 1;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				//arr[end] > arr[end + 1]
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
				arr[end + gap] = tmp;
			}
		}
	}
}

//直接选择排序
void SelectSort(int* arr, int n)
{
	int begin = 0;
	int end = n - 1;

	while (begin < end)
	{
		int min = begin, max = begin;
		//找最大最小值
		for (int i = begin + 1; i <= end; i++)
		{
			//最小值
			if (arr[i] < arr[min])
			{
				min = i;
			}
			//最大值
			if (arr[i] > arr[max])
			{
				max = i;
			}
		}
		//避免max和begin在同一个位置
		if (max == begin)
		{
			max = min;
		}
		Swap(&arr[min], &arr[begin++]);
		Swap(&arr[max], &arr[end--]);
	}
}

//快速排序

//hoare版本找基准值
int _HoareQuickSort(int* arr, int left, int right)
{
	int key = left;
	left++;

	while (left <= right)
	{
		//找比基准值大的值
		while (left <= right && arr[right] > arr[key])
		{
			right--;
		}
		//找比基准值小的值
		while (left <= right && arr[left] < arr[key])
		{
			left++;
		}

		//防止最后一次 left <= right
		if (left <= right)
		{
			Swap(&arr[left++], &arr[right--]);
		}
	}

	//left > right,key == 0,arr[right] < arr[key]
	//基准值与arr[right]交换
	Swap(&arr[key], &arr[right]);
	
	//返回基准值下标位置
	return right;
}

//挖坑法找基准值
int _PitQuickSort(int* arr, int left, int right)
{
	int hole = left;//坑
	int key = arr[hole];//基准值

	int num = 0;
	while (left < right)
	{
		测试死循环
		//printf("%d\n", ++num);

		//找比基准值小的值
		while (left < right && arr[right] >= key)
		{
			right--;
		}
		arr[hole] = arr[right];//将找到的值放入坑内
		hole = right;//记录坑的位置

		//找比基准值大的值
		while (left < right && arr[left] < key)
		{
			left++;
		}
		arr[hole] = arr[left];//将找到的值放入坑内
		hole = left;//记录坑的位置
	}

	arr[hole] = key;
	return hole;
}

//lomuto前后指针找基准值
int _LomutoQuickSort(int* arr, int left, int right)
{
	int prev = left, pcur = left + 1;
	int key = left;

	while (pcur <= right)
	{
		//寻找比基准值小的值
		if (arr[pcur] < arr[key] && ++prev != pcur) 
		{
			Swap(&arr[pcur], &arr[prev]);
		}
		pcur++;
	}
	Swap(&arr[key], &arr[prev]);
	return prev;
}

//快速排序
void QuickSort(int* arr, int left,int right)
{
	if (left >= right)
	{
		return;
	}
	//找基准值
	int key = _PitQuickSort(arr, left, right);
	//左子序列
	QuickSort(arr, left, key - 1);
	//右子序列
	QuickSort(arr, key + 1, right);
}



//非递归快速排序
//借用数据结构-栈
void StackQuickSort(int* arr, int left, int right)
{
	ST st;
	STInit(&st);
	StackPush(&st, right);
	StackPush(&st, left);

	while (!StackEmpty(&st))
	{
		//取左右栈顶
		int begin = StackTop(&st);
		StackPop(&st);
		int end = StackTop(&st);
		StackPop(&st);
		
		int prev = begin;
		int pcur = begin + 1;
		int key = begin;

		//双指针法找基准值
		while (pcur <= end)
		{
			if (arr[pcur] < arr[key] && ++prev != pcur)
			{
				Swap(&arr[prev], &arr[pcur]);
			}
			pcur++;
		}
		Swap(&arr[prev], &arr[key]);

		key = prev;
		//基准值划分左右区间:[begin,key-1],[key+1,end]
		if (key + 1 < end)
		{
			StackPush(&st, end);
			StackPush(&st, key + 1);
		}
		if (key - 1 > begin)
		{
			StackPush(&st, key - 1);
			StackPush(&st, begin);
		}
	}
	STDestroy(&st);
}

//归并排序
void _MergeSort(int* arr, int left, int right, int* tmp)
{
	if (left >= right)
	{
		return;
	}

	int mid = (left + right) / 2;
	_MergeSort(arr, left, mid, tmp);
	_MergeSort(arr, mid + 1, right, tmp);

	//合并 [left,mid] [mid+1,right]
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int index = begin1;

	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] < arr[begin2])
		{
			tmp[index++] = arr[begin1++];
		}
		else
		{
			tmp[index++] = arr[begin2++];
		}
	}

	// begin1 || begin1  越界
	while (begin1 <= end1)
	{
		tmp[index++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[index++] = arr[begin2++];
	}

	//拷贝tmp
	for (int i = left; i <= right; i++)
	{
		arr[i] = tmp[i];
	}
}

void MergeSort(int* arr, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);

	_MergeSort(arr, 0, n - 1, tmp);

	free(tmp);
	tmp = NULL;
}

//计数排序
void ConunSort(int* arr, int n)
{
	int max = arr[0], min = arr[0];

	//找最大值和最小值的差值
	for (int i = 1; i < n; i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
		if (arr[i] < min)
		{
			min = arr[i];
		}
	}
	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
		perror("malloc fail!!!");
		exit(1);
	}

	//初始化数组
	memset(count, 0, range * sizeof(int));

	//统计数组每个数据出现的次数
	for (int i = 0; i < n; i++)
	{
		count[arr[i] - min]++;
	}
	//取count数据放入arr中
	int index = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			arr[index++] = i + min;
		}
	}
}

main.cpp

#include"Sort.h"

void prarr(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

void test01()
{
	srand(time(0));
	int numsize = 50000;
	int begin = 0;
	int end = 0;

	int* a1 = (int*)malloc(sizeof(int) * numsize);
	int* a2 = (int*)malloc(sizeof(int) * numsize);
	int* a3 = (int*)malloc(sizeof(int) * numsize);
	int* a4 = (int*)malloc(sizeof(int) * numsize);
	int* a5 = (int*)malloc(sizeof(int) * numsize);
	int* a6 = (int*)malloc(sizeof(int) * numsize);
	int* a7 = (int*)malloc(sizeof(int) * numsize);
	int* a8 = (int*)malloc(sizeof(int) * numsize);
	int* a9 = (int*)malloc(sizeof(int) * numsize);
	
	for (int i = 0; i < numsize; i++)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
		a8[i] = a1[i];
		a9[i] = a1[i];
	}

	//冒泡排序
	begin = clock();
	BubbleSort(a1, numsize);
	end = clock();
	printf("冒泡排序:%d\n",end-begin);

	//堆排序
	begin = clock();
	HeapSortSmall(a2, numsize);
	end = clock();
	printf("堆排序:%d\n", end - begin);

	//直接插入排序
	begin = clock();
	InsertSort(a3, numsize);
	end = clock();
	printf("直接插入排序:%d\n", end - begin);

	//希尔排序
	begin = clock();
	ShellSort(a4, numsize);
	end = clock();
	printf("希尔排序:%d\n", end - begin);

	//直接选择排序
	begin = clock();
	SelectSort(a5, numsize);
	end = clock();
	printf("直接选择排序:%d\n", end - begin);

	//快速排序
	begin = clock();
	QuickSort(a6, 0, numsize - 1);
	end = clock();
	printf("快速排序:%d\n", end - begin);

	//非递归快速排序
	begin = clock();
	StackQuickSort(a7, 0, numsize - 1);
	end = clock();
	printf("非递归快速排序:%d\n", end - begin);

	//归并排序
	begin = clock();
	MergeSort(a8, numsize);
	end = clock();
	printf("归并排序:%d\n", end - begin);

	//计数排序
	begin = clock();
	ConunSort(a9, numsize);
	end = clock();
	printf("计数排序:%d\n", end - begin);

	free(a1);
	free(a2);
	free(a3);
	free(a4);
	free(a5);
	free(a6);
	free(a7);
	free(a8);
	free(a9);
	a1 = NULL;
	a2 = NULL;
	a3 = NULL;
	a4 = NULL;
	a5 = NULL;
	a6 = NULL;
	a7 = NULL;
	a8 = NULL;
	a9 = NULL;
}

int main()
{
	//int arr[10] = { 10,6,7,5,3,4,8,2,1,9 };
	//printf("排序前:");
	//prarr(arr,10);

	BubbleSort(arr, 10);
	HeapSortSmall(arr, 10);
	InsertSort(arr, 10);
	ShellSort(arr, 10);
	SelectSort(arr, 10);
	QuickSort(arr, 0, 9);
	StackQuickSort(arr, 0, 9);
	MergeSort(arr, 10);
	//ConunSort(arr, 10);

	//printf("排序后:");
	//prarr(arr, 10);

	//测试
	test01();
	return 0;
}

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

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

相关文章

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 9月7日,星期六

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年9月7日 星期六 农历八月初五 白露 1、 司法部&#xff1a;遏制地方乱发文、出台“奇葩”政策文件等情况。 2、 证监会&#xff1a;拉长离职人员入股禁止期至10年&#xff0c;扩大对离职人员从严监管范围。 3、 全国医护比…

三文带你轻松上手鸿蒙的AI语音03-文本合成声音

三文带你轻松上手鸿蒙的AI语音03-文本合成声音 前言 接上文 三文带你轻松上手鸿蒙的AI语音02-声音文件转文本 HarmonyOS NEXT 提供的AI 文本合并语音功能&#xff0c;可以将一段不超过10000字符的文本合成为语音并进行播报。 场景举例 手机在无网状态下&#xff0c;系统应用…

超声波测距模块HC-SR04(基于STM32F103C8T6HAL库)

超声波测距模块参考资料 1.电路连接及引脚配置 触发信号PA3只需要输出10us的高电平&#xff0c;所以直接设置成 普通的GPIO端口即可&#xff1b;回响信号使用外部中断&#xff0c;上升沿信号产生外部中断&#xff0c;打开定时器&#xff0c;下降沿再产生一次中断&#xff0c;读…

飞特STS3315基本使用方法

宁天道/FeelECH 01-介绍 串口总线舵机&#xff0c;可以通过一根线将多个舵机串联在一起&#xff0c;一个串口线片可以控制所有的舵机。 内带闭环&#xff0c;可以自定义舵机移动的最大速度&#xff0c;加速度&#xff0c; 可以修改各种模式&#xff0c;满足各种各样的需求&…

OTN光传送网-介绍

1. 引用 OTN光传送网--华为设备_otn传输设备建设方案-CSDN博客 OTN光传送网&#xff08;Optical Transport Network&#xff09;&什么是OTN-CSDN博客 https://zhuanlan.zhihu.com/p/403304019 术语&#xff1a; 英文缩写描述灰光模块彩光模块CWDM&#xff1a;Coarse Wa…

欺诈文本分类检测(十三):交叉训练验证

1. 引言 交叉验证主要讨论的是数据集的划分问题。 通常情况下&#xff0c;我们会采用均匀随机抽样的方式将数据集划分成3个部分——训练集、验证集和测试集&#xff0c;这三个集合不能有交集&#xff0c;常见的比例是8:1:1&#xff08;如同前文我们所作的划分)。这三个数据集…

吉利星座03组卫星发射

北京时间2024年9月6日2时30分&#xff0c;在太原卫星发射中心使用长征六号运载火箭&#xff0c;成功将民营“中国星链”——吉利未来出行星座第三个轨道面、吉利星座03组卫星发射升空&#xff0c;10颗卫星顺利进入预定轨道&#xff0c;发射任务获得圆满成功。此次任务是长征系列…

飞思相机存储卡格式化数据如何恢复?提供全面指南

在数字摄影时代&#xff0c;‌飞思相机以其卓越的成像质量和专业的性能&#xff0c;‌赢得了众多摄影师的青睐。‌然而&#xff0c;‌即使是专业的设备也难免遭遇数据丢失的困境&#xff0c;‌尤其是当存储卡不幸被格式化时。‌面对这一突如其来的灾难&#xff0c;‌许多摄影师…

qt QGraphicsScene场景坐标和场景内GraphicsItem局部坐标的相互转换

为了更清晰地解释场景坐标与局部坐标之间的转换过程&#xff0c;我们可以通过一个简单的实例来演示如何赋值场景坐标&#xff0c;并将其转换为图形项的局部坐标。 实例步骤 假设我们有一个场景 QGraphicsScene 和一个矩形图形项 QGraphicsRectItem&#xff0c;矩形的大小为 1…

Redis进阶(六):缓存

1.缓存 速度快的设备可以作为速度慢的设备的缓存 缓存能够有意义&#xff1a;二八定律&#xff0c;20%的数据可以应对80%的请求 通常使用redis作为数据库的缓存&#xff08;mysql&#xff09; 数据库是非常重要的组件&#xff0c;mysql速度比较慢 因为mysql等数据库&#x…

【 C++ 】类和对象的学习(三)

前言&#xff1a; &#x1f618;我的主页&#xff1a;OMGmyhair-CSDN博客 目录 一、初始化列表 二、类型转换 三、static成员 四、友元 五、内部类 六、匿名对象 一、初始化列表 当我们之前在写构造函数时&#xff0c;我们通常在构造函数内对成员变量进行赋值。但其实还…

系统架构师考试学习笔记第三篇——架构设计高级知识(19)嵌入式系统架构设计理论与实践

本章考点&#xff1a; 第19课时主要学习嵌入式系统架构设计的理论和工作中的实践。根据新版考试大纲&#xff0c;本课时知识点会涉及案例分析题&#xff08;25分&#xff09;。在历年考试中&#xff0c;案例题对该部分内容都有固定考查&#xff0c;综合知识选择题目中有固定分值…

北大港中文腾讯提出ViewCrafter:一张图像就可以制作影视特效和游戏画面!

北大和港中文联合腾讯人工智能实验室提出了 ViewCrafter&#xff0c;这是一种利用视频扩散模型的先验从单个或稀疏图像合成一般场景的高保真新视图的新方法。 可以简单理解为将复杂的图像转换成新角度的图像版本。首先&#xff0c;它会使用特殊的算法来读取一张或几张图像&…

SpringBoot项目-实现简单的CRUD功能和分页查询

背景 本博文主要是创建了一个新的SpringBoot项目&#xff0c;实现基本的增删改查&#xff0c;分页查询&#xff0c;带条件的分页查询功能。是方便初学者学习后端项目的一个比较清晰明了的实践代码&#xff0c;读者可根据博文&#xff0c;从自己动手创建一个新的SpringBoot项目…

Scratch教师节 —— 感恩教师节

小虎鲸Scratch资源站-免费Scratch作品源码,素材,教程分享平台! Scratch教师节动画作品——感恩教师节 在这个特别的日子里&#xff0c;我们迎来了教师节。为了表达对老师们的感激之情&#xff0c;Scratch平台上的小朋友们用创意与热情制作了精彩的动画作品——“感恩教师节”。…

在国产芯片上实现YOLOv5/v8图像AI识别-【4.3】RK3588使用yolov8+bytetrack实现跟踪更多内容见视频

本专栏主要是提供一种国产化图像识别的解决方案&#xff0c;专栏中实现了YOLOv5/v8在国产化芯片上的使用部署&#xff0c;并可以实现网页端实时查看。根据自己的具体需求可以直接产品化部署使用。 B站配套视频&#xff1a;https://www.bilibili.com/video/BV1or421T74f 背景…

【Canvas与艺术】四叶花

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>386.四叶花</title><style type"text/css">.c…

GDB watch starti i files

watch break starti 在程序的最初开始运行的位置处断下来 ​​ i files 查看程序及加载的 so 的 sections ​​

【Ubuntu】环境准备

平时不怎么接触运维。linux的东西都快忘完了&#xff0c;正好最近腾讯云优惠&#xff0c;38元一年&#xff0c;优惠拉满&#xff0c;拿下一个玩一玩&#xff0c;可以当小程序的服务器&#xff0c;记录一些常用的操作&#xff0c;省的每次用的时候都想不起来 1.有一个linux系统…

对接后端download接口报未知异常错误

你一定遇到过这种情况&#xff0c;在一个项目中下载功能明明好好的&#xff0c;下载接口调用方法与前端调用方法封装的好好的&#xff0c;可是换了一个接口&#xff0c;竟然搞罢工了&#xff0c;类似下面这样的&#xff0c;你会不会无从下手&#xff0c;不知道该怎么办呢&#…