C语言排序集合:1.直接插入排序 2.希尔排序 3.直接选择排序 4.冒泡排序 5.堆排序 6.快速排序(三种方法实现) 7.归并排序(非递归+递归)8.计数排序 + 排序速度测试

目录

1.直接插入排序

2.希尔排序

3.直接选择排序

4.冒泡排序

5.堆排序

6.快速排序(三种方法实现)

法1:挖坑法

法2:前后指针法

法3:左右指针法

7.归并排序

1.递归

2.非递归

8.计数排序

9.检测结果

10.排序速度检测

1.快速排序不用小区间优化

2.快速排序用小区间优化

结论

代码

未完待续(以后还会加排序)!


本次排序所使用的头文件有:
#include
#include
#include

#include

1.直接插入排序

//直接插入排序---"摸牌"---升序
//最坏结果(逆序)---O(N^2)
//最好结果(顺序有序)---O(N)
//算是在O(N^2)中最好的
void InsertSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		//有序数组(数组[a, end]有序)的末尾下标---有序牌的最后一张
		int end = i;
		//要插入的数---要摸的牌
		int tmp = a[end + 1];
		while (end >= 0)
		{
			//比较看是否要插入牌
			if (a[end] > tmp)
			{
				//往后挪
				a[end + 1] = a[end];
				//向前继续比较
				end--;
			}
			else//符合
			{
				break;
			}
		}

		//插入数据(牌)
		a[end + 1] = tmp;
	}
}

2.希尔排序

//希尔排序---O(N^1.3)
//1.gap > 1 进行gap组间隔为gap的序排序
//2.gap == 1 进行直接插入排序
void ShellSort(int* a, int n)
{
	int gap = n;

	while (gap > 1)
	{
		//确保gap最后为1(进行直接插入排序)
		gap = gap / 3 + 1;
		//多组并排
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				//升序
				if (a[end] > tmp)
				{
					//往后间隔gap处挪
					a[end + gap] = a[end];
					//往前间隔gap处找
					end -= gap;
				}
				else
				{
					break;
				}
			}

			//插入
			a[end + gap] = tmp;
		}
	}
}

3.直接选择排序

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}


//直接选择排序---O(N^2)
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int maxi = begin, mini = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] > a[maxi])
				maxi = i;
			if (a[i] < a[mini])
				mini = i;
		}
		Swap(&a[begin], &a[mini]);
		//防止maxi在begin处被换走
		if (maxi == begin)
			maxi = mini;
		Swap(&a[end], &a[maxi]);
		begin++;
		end--;
	}
}

4.冒泡排序

//冒泡排序---O(N^2)
void BubbleSort(int* a, int n)
{
	int flag = 0;
	for (int i = 0; i < n; i++)
	{
		int falg = 1;
		for (int j = 0; j < n - 1 - i; j++)
		{
			if (a[j] > a[j + 1])
			{
				flag = 0;
				int tmp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = tmp;
			}
		}
		if (flag)
			break;
	}
}

5.堆排序

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//向下调整--前提左右子树是堆
void AdjustDown(int* a, int n, int parent)
{
	//假设最大孩子为左孩子
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
//堆排序---升序建大堆,反之---O(N*logN)
void HeapSort(int* a, int n)
{
	//1.向下调整逆着建堆---叶子节点不用
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		//2.首尾交换---此法尽量地减少parent与child之间关系的改变
		Swap(&a[0], &a[end]);
		//3.不包括尾继续向下调整建堆
		AdjustDown(a, end, 0);
		end--;
	}
}

6.快速排序(三种方法实现)

法1:挖坑法

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//三数先其中(选出前中后中第二大的数,返回其下标)
int GetMIdIndex(int* a, int left, int right)
{
	int mid = (left + right) >> 1;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
			return mid;
		else if (a[left] < a[right])
			return right;
		else
			return left;

	}
	else
	{
		if (a[mid] > a[right])
			return mid;
		else if (a[left] > a[right])
			return right;
		else
			return left;
	}
}
//快速排序--挖坑法---O(N*logN)
void QuickSort1(int* a, int left, int right)
{
	//跳出条件
	if (left >= right)
		return;
	//三数先其中(选出前中后中第二大的数,返回其下标)---防止出现有序情况时时间复杂度为O(N^2)
	int index = GetMIdIndex(a, left, right);
	Swap(&a[left], &a[index]);
	int begin = left;
	int end = right;
	int pivot = begin;
	int key = a[begin];

	while (begin < end)
	{
		//坑在左,end向左找小填坑
		while (begin < end && a[end] >= key)
			end--;
		//填坑
		a[pivot] = a[end];
		//形成新坑
		pivot = end;
		//坑在右,begin向左找大填坑
		while (begin < end && a[begin] <= key)
			begin++;

		//填坑
		a[pivot] = a[begin];
		//形成新坑
		pivot = begin;
	}
	//相遇处为坑
	pivot = begin;
	//把a[keyi]填在相遇处的坑上
	a[pivot] = key;

	//递归
	QuickSort1(a, left, pivot - 1);
	QuickSort1(a, pivot + 1, right);
	//小区间优化---多数据时用可以加快排序速度
	//if (pivot - 1 - left > 100)
	//{
	//	QuickSort1(a, left, pivot - 1);
	//}
	//else
	//{
	//	//用直接插入排序
	//	InsertSort(a + left, pivot - 1 - left + 1);
	//}
	//if (right - (pivot + 1) > 100)
	//{

	//	QuickSort1(a, pivot + 1, right);
	//}
	//else
	//{
	//	//用直接插入排序
	//	InsertSort(a + pivot + 1, right - (pivot + 1) + 1);
	//}
}

法2:前后指针法

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//三数先其中(选出前中后中第二大的数,返回其下标)
int GetMIdIndex(int* a, int left, int right)
{
	int mid = (left + right) >> 1;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
			return mid;
		else if (a[left] < a[right])
			return right;
		else
			return left;

	}
	else
	{
		if (a[mid] > a[right])
			return mid;
		else if (a[left] > a[right])
			return right;
		else
			return left;
	}
}
//快速排序--前后指针法---O(N*logN)
void QuickSort2(int* a, int left, int right)
{
	//跳出条件
	if (left >= right)
		return;
	//三数先其中(选出前中后中第二大的数,返回其下标)---防止出现有序情况时时间复杂度为O(N^2)
	int index = GetMIdIndex(a, left, right);
	Swap(&a[left], &a[index]);
	//前指针
	int prev = left;
	//当前指针
	int cur = prev + 1;
	int keyi = prev;

	while (cur <= right)
	{
		//找小
		if (a[cur] < a[keyi] && ++prev < cur)
			Swap(&a[prev], &a[cur]);

		cur++;
	}
	//让a[keyi]去到适合它的位置
	//使下标[left, prev - 1]的值小于下标keyi的值,下标[prev + 1, right]的值大于下标keyi的值
	Swap(&a[keyi], &a[prev]);

	//递归
	QuickSort2(a, left, prev - 1);
	QuickSort2(a, prev + 1, right);
	//小区间优化---多数据时用可以加快排序速度
	//if (prev - 1 - left > 100)
	//{
	//	QuickSort2(a, left, prev - 1);
	//}
	//else
	//{
	//	//用直接插入排序
	//	InsertSort(a + left, prev - 1 - left + 1);
	//}
	//if (right - (prev + 1) > 100)
	//{

	//	QuickSort2(a, prev + 1, right);
	//}
	//else
	//{
	//	//用直接插入排序
	//	InsertSort(a + prev + 1, right - (prev + 1) + 1);
	//}
}

法3:左右指针法

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//三数先其中(选出前中后中第二大的数,返回其下标)
int GetMIdIndex(int* a, int left, int right)
{
	int mid = (left + right) >> 1;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
			return mid;
		else if (a[left] < a[right])
			return right;
		else
			return left;

	}
	else
	{
		if (a[mid] > a[right])
			return mid;
		else if (a[left] > a[right])
			return right;
		else
			return left;
	}
}
//快速排序--左右指针法---O(N*logN)
void QuickSort3(int* a, int left, int right)
{
	//跳出条件
	if (left >= right)
		return;
	//三数先其中(选出前中后中第二大的数,返回其下标)---防止出现有序情况时时间复杂度为O(N^2)
	int index = GetMIdIndex(a, left, right);
	Swap(&a[left], &a[index]);
	//前指针
	int begin = left;
	//当前指针
	int end = right;
	int keyi = begin;

	while (begin < end)
	{
		//找小
		while (begin < end && a[end] >= a[keyi])
			end--;

		//找大
		while (begin < end && a[begin] <= a[keyi])
			begin++;

		//交换	
		Swap(&a[begin], &a[end]);
	}
	//让key去到适合它的位置
	//使下标[left, begin - 1]的值小于key,下标[begin + 1 right]的值大于下标key
	Swap(&a[keyi], &a[begin]);

	//递归
	QuickSort3(a, left, begin - 1);
	QuickSort3(a, begin + 1, right);
	//小区间优化---多数据时用可以加快排序速度
	//if (begin - 1 - left > 100)
	//{
	//	QuickSort3(a, left, begin - 1);
	//}
	//else
	//{
	//	//用直接插入排序
	//	InsertSort(a + left, begin - 1 - left + 1);
	//}
	//if (right - (begin + 1) > 100)
	//{

	//	QuickSort3(a, begin + 1, right);
	//}
	//else
	//{	//用直接插入排序
	//	InsertSort(a + begin + 1, right - (begin + 1) + 1);
	//}
}

7.归并排序

1.递归

//归并排序--递归
void _MergeSort(int* a, int left, int right, int* tmp)
{
	if (left == right)
		return;
	int mid = (left + right) / 2;
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;

	int k = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[k++] = a[begin1++];
		}
		else
		{
			tmp[k++] = a[begin2++];
		}
	}
	

	//补上
	while (begin1 <= end1)
	{
		tmp[k++] = a[begin1++];
	}	
	while (begin2 <= end2)
	{
		tmp[k++] = a[begin2++];
	}
	//把tmp拷贝回a
	memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));

}

2.非递归


//归并排序--非递归
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	int gap = 1;
	while (gap < n)
	{
		int  k = 0;
		for (int i = 0; i < n; i += gap * 2)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + gap*2 - 1;

			if (end1 >= n || begin2 >= n)
			{
				//不归并
				break;
			}
			if (end2 >= n)
			{
				//修改正确区间,以完成最后的归并
				end2 = n - 1;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[k++] = a[begin1++];
				}
				else
				{
					tmp[k++] = a[begin2++];
				}
			}


			//补上
			while (begin1 <= end1)
			{
				tmp[k++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[k++] = a[begin2++];
			}
			//把tmp拷贝回a
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));

		}
		gap *= 2;
	}

	free(tmp);
}

8.计数排序

//计数排序
//计数排序---时间复杂度最好为O(n)
//缺陷1:只能排序整型
//缺陷2:主要适用于范围居中的数据
void CountSort(int* a, int n)
{
	int max = a[0], min = a[0];
	for (int i = 0; i < n; i++)
	{
		if (a[i] > max)
			max = a[i];

		if (a[i] < min)
			min = a[i];
	}
	int range = max - min + 1;
	int* countA = (int*)malloc(sizeof(int) * range);
	//全部归零
	memset(countA, 0, sizeof(int) * range);

	//相对映射---减少内存的开辟
	for (int i = 0; i < n; i++)
	{
		countA[a[i] - min]++;
	}

	//计数
	int k = 0;
	for (int i = 0; i < range; i++)
	{
		while (countA[i]--)
		{
			a[k++] = i + min;
		}
	}
	free(countA);
}

9.检测结果

C语言排序集合:1.直接插入排序 2.希尔排序 3.直接选择排序 4.冒泡排序 5.堆排序 6.快速排序(三种方法实现) 7.归并排序(非递归+递归)8.计数排序 + 排序速度测试_第1张图片

排序结果正确 

代码:

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

void TestMergeSort()
{
	int a[] = { 2,1,5,3,9,4,6,8,7 };
	int sz = sizeof(a) / sizeof(a[0]);

	PrintArray(a, sz);
	MergeSort(a, sz);
	PrintArray(a, sz);
}

void TestQuickSort1()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	QuickSort1(a, 0, sz - 1);
	PrintArray(a, sz);
}
void TestQuickSort2()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	QuickSort2(a, 0, sz - 1);
	PrintArray(a, sz);
}
void TestQuickSort3()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	QuickSort3(a, 0, sz - 1);
	PrintArray(a, sz);
}
void TestInsertSort()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	InsertSort(a, sz);
	PrintArray(a, sz);
}
void TestSellSort()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	ShellSort(a, sz);
	PrintArray(a, sz);
}
void TestBubbleSort()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	BubbleSort(a, sz);
	PrintArray(a, sz);
}

void TestSelectSort()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	SelectSort(a, sz);
	PrintArray(a, sz);
}

void TestHeapSort()
{
	int a[] = { 1,5,3,6,9,8,2,4,7 };
	int sz = sizeof(a) / sizeof(a[0]);
	PrintArray(a, sz);
	HeapSort(a, sz);
	PrintArray(a, sz);
}
int main()
{
	TestInsertSort();
	TestSellSort();
	TestBubbleSort();
	TestSelectSort();
	TestHeapSort();
	TestQuickSort1();
	TestQuickSort2();
	TestQuickSort3();
	TestMergeSort();
	return 0;
}


10.排序速度检测

十万个随机数排序,结果单位为毫秒

1.快速排序不用小区间优化

结果

 C语言排序集合:1.直接插入排序 2.希尔排序 3.直接选择排序 4.冒泡排序 5.堆排序 6.快速排序(三种方法实现) 7.归并排序(非递归+递归)8.计数排序 + 排序速度测试_第2张图片

2.快速排序用小区间优化

结果

C语言排序集合:1.直接插入排序 2.希尔排序 3.直接选择排序 4.冒泡排序 5.堆排序 6.快速排序(三种方法实现) 7.归并排序(非递归+递归)8.计数排序 + 排序速度测试_第3张图片

结论

1.排序速度第一梯队:计数排序(局限性大)、希尔排序、快速排序、堆排序、归并排序

2.排序速度第二梯队:直接插入排序(在此梯队的大哥)、冒泡排序(小老弟一个)、直接选择排序

3.快排用小区间优化效果并不明显(但当数据量非常大时还是可以加快排序速度的)

代码


void TestOP()
{

	srand((unsigned int)time(NULL));
	int n = 100000;
	int* a1 = (int*)malloc(sizeof(int) * n);
	int* a2 = (int*)malloc(sizeof(int) * n);
	int* a3 = (int*)malloc(sizeof(int) * n);
	int* a4 = (int*)malloc(sizeof(int) * n);
	int* a5 = (int*)malloc(sizeof(int) * n);
	int* a6 = (int*)malloc(sizeof(int) * n);
	int* a7 = (int*)malloc(sizeof(int) * n);
	int* a8 = (int*)malloc(sizeof(int) * n);
	int* a9 = (int*)malloc(sizeof(int) * n);
	int* a10 = (int*)malloc(sizeof(int) * n);
	int* a11 = (int*)malloc(sizeof(int) * n);
	for (int i = 0; i < n; 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];
		a10[i] = a1[i];
		a11[i] = a1[i];

	}

	int begin1 = clock();//系统启动到这的时间点---毫秒
	InsertSort(a1, n);
	int end1 = clock();//系统启动到这的时间点---毫秒

	int begin2 = clock();
	ShellSort(a2, n);
	int end2 = clock();

	int begin3 = clock();
	BubbleSort(a3, n);
	int end3 = clock();

	int begin4 = clock();
	SelectSort(a4, n);
	int end4 = clock();
	int begin5 = clock();
	HeapSort(a5, n);
	int end5 = clock();

	int begin6 = clock();
	QuickSort1(a6, 0, n - 1);
	int end6 = clock();
	int begin7 = clock();
	QuickSort2(a7, 0, n - 1);
	int end7 = clock();
	int begin8 = clock();
	QuickSort3(a8, 0, n - 1);
	int end8 = clock();
	int begin9 = clock();
	MergeSort(a9, n);
	int end9 = clock();	
	int begin10 = clock();
	MergeSortNonR(a10, n);
	int end10 = clock();	
	int begin11 = clock();
	CountSort(a11, n);
	int end11 = clock();
	printf("InsertSort: %d\n", end1 - begin1);
	printf("ShellSort: %d\n", end2 - begin2);
	printf("BubbleSort: %d\n", end3 - begin3);
	printf("SelectSort: %d\n", end4 - begin4);
	printf("HeapSort: %d\n", end5 - begin5);
	printf("QuickSort1: %d\n", end6 - begin6);
	printf("QuickSort2: %d\n", end7 - begin7);
	printf("QuickSort3: %d\n", end8 - begin8);
	printf("MergeSort: %d\n", end9 - begin9);
	printf("MergeSortNonR: %d\n", end10 - begin10);
	printf("CountSort: %d\n", end11 - begin11);

	free(a1);
	free(a2);
	free(a3);
	free(a4);
	free(a5);
	free(a6);
	free(a7);
	free(a8);
	free(a9);
	free(a10);
	free(a11);

}
int main()
{

	//TestInsertSort();
	//TestSellSort();
	//TestBubbleSort();
	//TestSelectSort();
	//TestHeapSort();
	//TestQuickSort1();
	//TestQuickSort2();
	//TestQuickSort3();
	//TestMergeSort();
	//TestMergeSortNonR();
	//TestCountSort();
	TestOP();

	return 0;
}

未完待续(以后还会加排序)!

你可能感兴趣的:(排序算法,算法,数据结构)