4.7排序(C语言)

news2024/10/7 15:22:22

1.八大排序

343849bffbbc4cc19a5d673777bf3c1e.jpg

加一个计数排序(时间复杂度为O(n), 空间复杂度为O(max(n, range),非比较排序)。 

2.希尔排序

2118ea07e07243f99a497986c91d9dd9.jpg

3.三个O(n^2)的排序的比较

4e7498e3facd4b589695add52bbc16bd.jpg

4.归并排序和快速排序

0bdd228883cf4e96a1f17f5a465804ee.jpg

非递归:

130469d8bc404c51817617d0d29fecd1.jpg

817095b5a3834187a470b5c67f37a8d7.png

5.排序比较

注意: 下面4种高效排序中,综合性能最好的是快速排序,但是在全都是一个相同的数的情况下,快排的效率最低,因为它无法分成大小区间,在实际中,希尔排序用的比较少,它是数据越多,越无序,优势越明显,但是面对少量数据优势就变成了劣势,归并排序空间复杂度较高,堆排序要先建堆,精确的时间复杂度是O(n + nlogn)。具体效率见下图:

1.1 十万个随机数Debug模式下:

1.2 十万个随机数Release模式下:

2.1 百万个随机数Debug模式下:

2.2 百万个随机数Release模式下:

3.1 千万个随机数Debug模式下:

3.2 千万个随机数Release模式下:

6.稳定型:

数组中相同的值,在排序之后相对位置是否变化,如果可能会变,就是不稳定的,不变就是稳定的。

所有的排序都可以不稳定。

7.堆排序参考以下博客:

4.6.2二叉树(堆和堆排序)(C语言)

8.内排序和外排序

9.我的代码:

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDataType;     //重定义数据类型
typedef struct Stack
{
	STDataType* data;
	int top;                //栈顶
	int capacity;           //容量
}Stack;

extern void StackInit(Stack* ps);                         // 1.初始化栈 

extern void StackPush(Stack* ps, STDataType x);           // 2.入栈 

extern void StackPop(Stack* ps);                          // 3.出栈 

extern STDataType StackTop(Stack* ps);                    // 4.获取栈顶元素 

extern int StackSize(Stack* ps);                          // 5.获取栈中有效元素个数 

extern bool StackEmpty(Stack* ps);                        // 6.检测栈是否为空

extern void StackDestroy(Stack* ps);                      // 7.销毁栈 
#include"Stack.h"

void StackInit(Stack* ps)     // 1.初始化栈 
{
	assert(ps);

	ps->data = NULL;
	ps->capacity = 0;
	ps->top = 0;     //初始值是-1或0都可以,但是初始值不同,后期的操作不同

}

void StackPush(Stack* ps, STDataType x)     // 2.入栈 
{
	assert(ps);

	if (ps->capacity == ps->top)     //扩容
	{
		int newcapacity = ps->capacity > 0 ? 2 * ps->capacity : 4;     //考虑容量为0的情况
		STDataType* tmp = (STDataType*)realloc(ps->data, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)     //考虑扩容失败
		{
			perror("realloc:");
			return;
		}
		ps->data = tmp;
		ps->capacity = newcapacity;
	}

	ps->data[ps->top] = x;
	ps->top++;
}

void StackPop(Stack* ps)     // 3.出栈
{
	assert(ps);
	assert(!StackEmpty(ps));     //考虑栈空

	ps->top--;
}

STDataType StackTop(Stack* ps)     // 4.获取栈顶元素 
{
	assert(ps);
	assert(!StackEmpty(ps));     //考虑栈空

	return ps->data[ps->top - 1];
}

int StackSize(Stack* ps)     // 5.获取栈中有效元素个数 
{
	assert(ps);

	return ps->top;
}

bool StackEmpty(Stack* ps)         // 6.检测栈是否为空
{
	assert(ps);

	return ps->top == 0;
}

void StackDestroy(Stack* ps)     // 7.销毁栈 
{
	assert(ps);

	free(ps->data);
	ps->data = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<windows.h>
#include<string.h>

typedef int dataType;

// 打印
extern void PrintArray(dataType* a, int n);
// 插入排序
extern void InsertSort(dataType* a, int n);

// 希尔排序
extern void ShellSort(dataType* a, int n);

// 选择排序
extern void SelectSort(dataType* a, int n);

// 冒泡排序
extern void BubbleSort(dataType* a, int n);

// 堆排序
extern void HeapSort(dataType* a, int n);

// 快速排序
extern void QuickSort(dataType* a, int left, int right);

// 快速排序非递归
extern void QuickSortNonR(dataType* a, int left, int right);

// 归并排序递归
extern void MergeSort(dataType* a, int n);

// 归并排序非递归
extern void MergeSortNonR(dataType* a, int n);

// 计数排序
extern void CountSort(dataType* a, int n);
#include"Sort.h"
#include"Stack.h"

//交换两个数
void swap(dataType* pa, dataType* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}
// 打印
void PrintArray(dataType* a, int n)
{
	assert(a);
	for (int i = 0; i < n; ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

// 插入排序
void InsertSort(dataType* a, int n)
{
	assert(a);
	for (int i = 0; i < n - 1; ++i)
	{
		int end = i;
		int x = a[end + 1];
		while (end >= 0)
		{
			if (x < a[end])
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = x;
	}
}

// 希尔排序
void ShellSort(dataType* a, int n)
{
	int gap = n;
	//多次预排
	while (gap > 1) 
	{
		//确保最后一次gap是1
		//gap = gap / 3 + 1;
		gap = gap / 2;
		//一锅炖,一步到位
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int x = a[end + gap];
			while (end >= 0)
			{
				if (x < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = x;
		}
	}
}

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

	while (begin < end)
	{
		int iMax = begin;
		int iMin = end;
		//记录最大和最小的位置
		for (int i = begin; i <= end; ++i)
		{
			if (a[i] > a[iMax])
			{
				iMax = i;
			}
			if (a[i] < a[iMin])
			{
				iMin = i;
			}
		}
		swap(&a[iMin], &a[begin]);
		//考虑特殊情况,当最大值在第一个的时候,第一次交换会被换到最小值的位置
		if (iMax == begin)
		{
			iMax = iMin;
		}
		swap(&a[iMax], &a[end]);
		++begin;
		--end;
	}
}

//向下调整
void adjustDown(dataType* a, int n, int iParent)
{
	//假设左孩子大
	int iChild = iParent * 2 + 1;
	
	while (iChild < n)
	{
		//如果右孩子大
		if (iChild + 1 < n && a[iChild + 1] > a[iChild])
		{
			++iChild;
		}
		if (a[iChild] > a[iParent])
		{
			swap(&a[iChild], &a[iParent]);
			iParent = iChild;
			iChild = iParent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

// 堆排序
void HeapSort(dataType* a, int n)
{
	//先建立一个堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		adjustDown(a, n, i);
	}

	//堆顶元素和最后一个元素交换,剩下的继续向下调整
	int iEnd = n - 1;
	while (iEnd != 0)
	{
		adjustDown(a, iEnd + 1, 0);
		swap(&a[0], &a[iEnd]);
		--iEnd;
	}
}

// 冒泡排序
void BubbleSort(dataType* a, int n)
{
	int end = n;
	while (end > 0)
	{
		int flag = 0;
		for (int j = 1; j < end; ++j)
		{
			if (a[j - 1] > a[j])
			{
				swap(&a[j - 1], &a[j]);
				flag = 1;
			}
		}
		if (flag == 0)
		{
			break;
		}
		--end;
	}
}

//快排优化,三数取中
int getMidIndex(int* a, int left, int right)
{
	int iMid = left + ((right - left) >> 1);

	if (a[left] > a[iMid])
	{
		if (a[right] >= a[left])
		{
			return left;
		}
		else
		{
			return a[right] > a[iMid] ? right : iMid;
		}
	}
	else //a[left] <= a[iMid]
	{
		if (a[right] >= a[iMid])
		{
			return iMid;
		}
		else
		{
			return a[left] > a[right] ? left : right;
		}
	}
}

// 一次快排,左右指针法
int partSort1(int* a, int left, int right)
{
	//三数取中作为key
	int mid = getMidIndex(a, left, right);
	int iKey = left;
	swap(&a[iKey], &a[mid]);

	while (left < right)
	{
		//先从右边开始找小
		while (left < right && a[iKey] <= a[right])
		{
			--right;
		}
		//再从左边找大
		while (left < right && a[iKey] >= a[left])
		{
			++left;
		}
		//交换
		swap(&a[left], &a[right]);
	}
	//最后和iKey位置交换
	swap(&a[left], &a[iKey]);
	return left;
}

//一次快排,挖坑法
int partSort2(int* a, int left, int right)
{
	//三数取中作为key
	int mid = getMidIndex(a, left, right);
	int dig = left;
	swap(&a[dig], &a[mid]);

	//保存dig的值
	int key = a[dig];

	while (left < right)
	{
		//右边找小,和坑交换,并且作为新的坑
		while (left < right && a[right] >= key)
		{
			--right;
		}
		a[dig] = a[right];
		dig = right;

		//左边找大,和坑交换,并且作为新的坑
		while (left < right && a[left] <= key)
		{
			++left;
		}
		a[dig] = a[left];
		dig = left;
	}
	a[dig] = key;
	return dig;
}

//一次快排,前后指针法
int partSort3(int* a, int left, int right)
{
	int mid = getMidIndex(a, left, right);
	swap(&a[left], &a[mid]);
	int cur = left + 1;
	int prev = left;

	while (cur <= right)
	{
		//方法1
		/*while (cur <= right && a[cur] >= a[left])
		{
			++cur;
		}
		if (cur <= right)
		{
			++prev;
			swap(&a[cur], &a[prev]);
			++cur;
		}*/
		//方法2
		if (a[cur] < a[left] && ++prev != cur)
		{
			swap(&a[cur], &a[prev]);
		}
		++cur;
	}
	swap(&a[prev], &a[left]);
	return prev;
}

// 快速排序
void QuickSort(dataType* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}

	//小区间优化,使用直接插入排序
	if (right - left + 1 < 10)
	{
		InsertSort(a + left, right - left + 1);
	}

	//定义中间位置iKey
	int iKey = partSort3(a, left, right);

	//处理中间位置的左边
	QuickSort(a, left, iKey - 1);
	QuickSort(a, iKey + 1, right);
}

// 快速排序非递归
void QuickSortNonR(dataType* a, int left, int right)
{
	//使用栈存储区间
	Stack st;
	StackInit(&st);

	StackPush(&st, left);
	StackPush(&st, right);

	while (!StackEmpty(&st))
	{
		int end = StackTop(&st);
		//注意出栈的顺序
		StackPop(&st);
		int begin = StackTop(&st);
		StackPop(&st);
		int iKey = partSort3(a, begin, end);
		//[begin, iKey - 1] iKey [iKey + 1, end]
		if (iKey + 1 < end)
		{
			StackPush(&st, iKey + 1);
			StackPush(&st, end);
		}

		if (begin < iKey - 1)
		{
			StackPush(&st, begin);
			StackPush(&st, iKey - 1);
		}
	}
	StackDestroy(&st);
}

//归并排序递归法
void _MergeSort(dataType* a, int left, int right, dataType* tmp)
{
	if (left >= right)
	{
		return;
	}
	int mid = (left + right) / 2;
	//[left, mid] [mid + 1, right]
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid + 1, right, tmp);

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

	//比较,将小的放入临时数组中
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[i] = a[begin1];
			i++;
			begin1++;
		}
		else
		{
			tmp[i] = a[begin2];
			i++;
			begin2++;
		}
	}

	//处理尾巴
	//以下两个循环只会进一个
	while (begin1 <= end1)
	{
		tmp[i] = a[begin1];
		i++;
		begin1++;
	}

	while (begin2 <= end2)
	{
		tmp[i] = a[begin2];
		i++;
		begin2++;
	}

	//将tmp数组中的有序数组拷贝回原数组
	for (int j = left; j <= right; j++)
	{
		a[j] = tmp[j];
	}
}

// 归并排序
void MergeSort(dataType* a, int n)
{
	dataType* tmp = (dataType*)malloc(sizeof(dataType) * n);
	if (tmp == NULL)
	{
		perror("malloc:");
		exit(-1);
	}
	int left = 0;
	int right = n - 1;
	_MergeSort(a, left, right, tmp);

	free(tmp);
	tmp = NULL;
}

// 归并排序非递归
void MergeSortNonR(dataType* a, int n)
{
	dataType* tmp = (dataType*)malloc(sizeof(dataType) * n);
	if (tmp == NULL)
	{
		perror("malloc:");
		exit(-1);
	}

	//gap是一个区间的元素个数
	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			//[i, i + gap - 1] [i + gap, i + 2 * gap - 1]
			int begin1 = i;
			int end1 = i + gap - 1;
			int begin2 = i + gap;
			int end2 = i + 2 * gap - 1;
			int j = i;

			//三种边界情况处理
			//1.end2越界,此时[begin2, end2]区间不存在
			if (end1 >= n)
			{
				end1 = n - 1;
			}
			//2.begin2和end2越界
			//给个不存在的区间,避免重复录入数据
			if (begin2 >= n)
			{
				begin2 = n;
				end2 = n - 1;
			}
			//3.end2越界
			if (end2 >= n)
			{
				end2 = n - 1;
			}

			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] <= a[begin2])
				{
					tmp[j] = a[begin1];
					++j;
					++begin1;
				}
				else
				{
					tmp[j] = a[begin2];
					++j;
					++begin2;
				}
			}//end while

			while (begin1 <= end1)
			{
				tmp[j] = a[begin1];
				++j;
				++begin1;
			}

			while (begin2 <= end2)
			{
				tmp[j] = a[begin2];
				++j;
				++begin2;
			}
		}//end for

		//拷回原数组
		for (int i = 0; i < n; ++i)
		{
			a[i] = tmp[i];
		}

		gap *= 2;
	}//end while

	free(tmp);
	tmp = NULL;
}

// 计数排序
void CountSort(dataType* a, int n)
{
	//先找到最大值和最小值确定范围
	int max = a[0];
	int min = a[0];

	for (int i = 1; i < n; ++i)
	{
		if (a[i] > max)
		{
			max = a[i];
		}
		if (a[i] < min)
		{
			min = a[i];
		}
	}

	int count = max - min + 1;
	dataType* tmp = (dataType*)malloc(sizeof(dataType) * count);
	if (tmp == NULL)
	{
		perror("malloc:");
		exit(-1);
	}
	//数组全置0
	memset(tmp, 0, sizeof(dataType) * count);
	//保存数据个数
	for (int i = 0; i < n; ++i)
	{
		tmp[a[i] - min]++;
	}
	//写入原数组
	int j = 0;
	for (int i = 0; i < count; ++i)
	{
		int k = tmp[i];
		//写入重复的数据
		while (k-- != 0)
		{
			a[j] = i + min;
			++j;
		}
	}

	free(tmp);
	tmp = NULL;
}

#include"Sort.h"

void testInsertSort()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	InsertSort(arr, sizeof(arr) / sizeof(arr[0]));
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testShellSort()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	ShellSort(arr, sizeof(arr) / sizeof(arr[0]));
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testSelectSort()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	SelectSort(arr, sizeof(arr) / sizeof(arr[0]));
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testHeapSort()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testBubbleSort()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	BubbleSort(arr, sizeof(arr) / sizeof(arr[0]));
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testQuickSort()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	int n = sizeof(arr) / sizeof(arr[0]);
	QuickSort(arr, 0, n - 1);
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testQuickSortNonR()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	int n = sizeof(arr) / sizeof(arr[0]);
	QuickSortNonR(arr, 0, n - 1);
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testMergeSort()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	int n = sizeof(arr) / sizeof(arr[0]);
	MergeSort(arr, n);
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testMergeSortNonR()
{
	dataType arr[10] = { 5, 6, 4, 2, 8, 3, 7, 9, 1, 0 };
	int n = sizeof(arr) / sizeof(arr[0]);
	MergeSortNonR(arr, n);
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}

void testCountSort()
{
	dataType arr[14] = { 5, 6, 4, 2, 8, 3, 5, 5, 8, 6, 7, 9, 1, 0 };
	int n = sizeof(arr) / sizeof(arr[0]);
	CountSort(arr, n);
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
}
void test()
{
	//testInsertSort();
	//testShellSort();
	//testSelectSort();
	//testHeapSort();
	//testBubbleSort();
	//testQuickSort();
	//testQuickSortNonR();
	//testMergeSort();
	//testMergeSortNonR();
	//testCountSort();
}

//产生随机数
void getRandomNumber(dataType* array, int n)
{
	for (int i = 0; i < n; ++i)
	{
		array[i] = rand();
	}
}

//使用随机数测试性能
void testAll(int n)
{
	dataType* array = (dataType*)malloc(sizeof(dataType) * n);
	double begin = 0;
	double end = 0;

	/*getRandomNumber(array, n);
	begin = GetTickCount();
	InsertSort(array, n);
	end = GetTickCount();
	printf("直接插入排序:%.lfms\n", end - begin);*/

	getRandomNumber(array, n);
	begin = GetTickCount();
	ShellSort(array, n);
	end = GetTickCount();
	printf("希尔排序:%.lfms\n", end - begin);

	/*getRandomNumber(array, n);
	begin = GetTickCount();
	SelectSort(array, n);
	end = GetTickCount();
	printf("直接选择排序:%.lfms\n", end - begin);*/

	getRandomNumber(array, n);
	begin = GetTickCount();
	HeapSort(array, n);
	end = GetTickCount();
	printf("堆排序:%.lfms\n", end - begin);

	/*getRandomNumber(array, n);
	begin = GetTickCount();
	BubbleSort(array, n);
	end = GetTickCount();
	printf("冒泡排序:%.lfms\n", end - begin);*/

	getRandomNumber(array, n);
	begin = GetTickCount();
	QuickSort(array, 0, n - 1);
	end = GetTickCount();
	printf("快速排序递归法:%.lfms\n", end - begin);

	getRandomNumber(array, n);
	begin = GetTickCount();
	QuickSortNonR(array, 0, n - 1);
	end = GetTickCount();
	printf("快速排序非递归:%.lfms\n", end - begin);

	getRandomNumber(array, n);
	begin = GetTickCount();
	MergeSort(array, n);
	end = GetTickCount();
	printf("归并排序递归:%.lfms\n", end - begin);

	getRandomNumber(array, n);
	begin = GetTickCount();
	MergeSortNonR(array, n);
	end = GetTickCount();
	printf("归并排序非递归:%.lfms\n", end - begin);

	getRandomNumber(array, n);
	begin = GetTickCount();
	CountSort(array, n);
	end = GetTickCount();
	printf("计数排序:%.lfms\n", end - begin);
}

int main()
{
	//test();
	srand((unsigned)time(NULL));
	testAll(10000000);
	system("pause");
	return 0;
}

10答案代码:

// 插入排序
void InsertSort(int* a, int n);

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

void InsertSort(int* a, int n)
{
	assert(a);
	//最后一次,是要把n - 1这个数进行排序,则已经
	//排好序的尾部为n - 2
	for (int i = 0; i < n-1; ++i)
	{
		//end表示已经排好序的尾标
		int end = i;
		//首先保存要排序的数,一会就会被覆盖了
		int tmp = a[end + 1];
		//只要前面的数大于end + 1,则前面的这些数都向后挪动一个位置
		while (end >= 0 && a[end] > tmp)
		{
			a[end + 1] = a[end];
			--end;
		}
		a[end + 1] = tmp;
	}
}

void TestInsertSort()
{
	int a[] = { 3, 4, 6, 1, 2, 8, 3, 5, 7 };
	InsertSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

void ShellSort(int* a, int n)
{
	assert(a);

	int gap = n;
	//不能写成大于0,因为gap的值始终>=1
	while (gap > 1)
	{
		//只有gap最后为1,才能保证最后有序
		//所以这里要加1
		gap = gap / 3 + 1;
		//这里只是把插入排序的1换成gap即可
		//但是这里不是排序完一个分组,再去
		//排序另一个分组,而是整体只过一遍
		//这样每次对于每组数据只排一部分
		//整个循环结束之后,所有组的数据排序完成
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0 && a[end] > tmp)
			{
				a[end + gap] = a[end];
				end -= gap;
			}

			a[end + gap] = tmp;
		}
	}
}


void TestShellSort()
{
	int a[] = { 3, 4, 6, 1, 2, 8, 3, 5, 7 };
	ShellSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

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

// 快速排序递归实现
// 快速排序hoare版本
int PartSort1(int* a, int left, int right);
// 快速排序挖坑法
int PartSort2(int* a, int left, int right);
// 快速排序前后指针法
int PartSort3(int* a, int left, int right);
void QuickSort(int* a, int left, int right);

// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)

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



void BubbleSort(int* a, int n)
{
	assert(a);

	int end = n;
	while (end > 0)
	{
		/*
		加一个标记,如果中间没有发生交换
		说明前面的值都比后面的小
		即本身就是有序的,最好的情况下,
		它的时间复杂度就为N
		*/
		int flag = 0;
		for (int i = 1; i < end; ++i)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				flag = 1;
			}
		}

		if (flag == 0)
		{
			break;
		}

		--end;
	}
}

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

// 三数取中法,三个中取一个中间值

int GetMidIndex(int* a, int begin, int end)
{
	int mid = begin + ((end - begin) >> 1);
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
		{
			return mid;
		}
		else if (a[begin] > a[end])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
	else // begin >= 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 midindex = GetMidIndex(a, begin, end);
	Swap(&a[begin], &a[midindex]);

	int key = a[begin];
	int start = begin;
	/*
	这里要从右边走,如果从左边走,
	可能最后一步,如果找不到大于
	基准值的,会导致begin == end
	即相遇,但是右边还没有走,所以
	这里的值一定大于基准值,最后交换
	就会出问题,所以一定要从右边走,
	即使最后一次找不到小于基准值的,
	会和左边相遇,而左边此时还没走,
	一定比基准值小,最后交换肯定没有问题
	*/
	while (begin < end)
	{
		// end 找小
		while (begin < end && a[end] >= key)
			--end;

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

		Swap(&a[begin], &a[end]);
	}
  //最后的交换一定要保证a[begin] < a[start], 所以要从右边走
	Swap(&a[begin], &a[start]);
	return begin;
}

int PartSort2(int* a, int begin, int end)
{
	//begin是坑
	int key = a[begin];
	while (begin < end)
	{
		while (begin < end && a[end] >= key)
			--end;

		// end给begin这个坑,end就变成了新的坑。
		a[begin] = a[end];

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

		// end给begin这个坑,begin就变成了新的坑。
		a[end] = a[begin];
	}

	a[begin] = key;

	return begin;
}


/*
前后指针法
*/
int PartSort3(int* a, int begin, int end)
{
	int midindex = GetMidIndex(a, begin, end);
	Swap(&a[begin], &a[midindex]);

	int key = a[begin];
	int prev = begin;
	int cur = begin + 1;

	while (cur <= end)
	{
		// cur找小,把小的往前翻,大的往后翻
		if (a[cur] < key && ++prev != cur)
			Swap(&a[cur], &a[prev]);

		++cur;
	}

	Swap(&a[begin], &a[prev]);

	return prev;
}

// []
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;

	if (right - left + 1 < 10)
	{
		InsertSort(a+left, right - left + 1);
	}
	else
	{
		int div = PartSort3(a, left, right);
		//[left, div-1]
		//[div+1, right]
		QuickSort(a, left, div - 1);
		QuickSort(a, div + 1, right);
	}
}
//用栈模拟递归,用队列也可以实现
void QuickSortR(int* a, int left, int right)
{
	Stack st;
	StackInit(&st, 10);
	//先入大区间
	if (left < right)
	{
		StackPush(&st, right);
		StackPush(&st, left);
	}
	//栈不为空,说明还有没处理的区间
	while (StackEmpty(&st) != 0)
	{
		left = StackTop(&st);
		StackPop(&st);
		right = StackTop(&st);
		StackPop(&st);
		//快排单趟排序
		int div = PartSort1(a, left, right);
		// [left div-1]
		// 把大于1个数的区间继续入栈
		if (left < div - 1)
		{
			StackPush(&st, div - 1);
			StackPush(&st, left);
		}

		// [div+1, right]
		if (div+1 < right)
		{
			StackPush(&st, right);
			StackPush(&st, div + 1);
		}
	}

}

void TestQuickSort()
{
	int a[] = { 3, 4, 6, 1, 2, 8, 0, 5, 7 };
	QuickSortR(a, 0, sizeof(a) / sizeof(int)-1);
	PrintArray(a, sizeof(a) / sizeof(int));
}

// 归并排序递归实现
void MergeSort(int* a, int n)
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)

// 计数排序
void CountSort(int* a, int n)
void _MergeSort(int* a, int left, int right, int* tmp)
{
	if (left >= right)
		return;

	int mid = left + ((right - left) >> 1);

	// [left, mid]
	// [mid+1, right]
	_MergeSort(a, left, mid, tmp);
	_MergeSort(a, mid+1, right, tmp);

	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int index = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
			tmp[index++] = a[begin1++];
		else
			tmp[index++] = a[begin2++];
	}

	while (begin1 <= end1)
	{
		tmp[index++] = a[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[index++] = a[begin2++];
	}

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


void MergeSort(int* a, int n)
{
	assert(a);
	int* tmp = (int*)malloc(sizeof(int)*n);
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
}

/*
非递归排序与递归排序相反,将一个元素与相邻元素构成有序数组,
再与旁边数组构成有序数组,直至整个数组有序。
要有mid指针传入,因为不足一组数据时,重新计算mid划分会有问题
需要指定mid的位置
*/
void merge(int* a, int left, int mid, int right, int* tmp)
{
	// [left, mid]
	// [mid+1, right]
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int index = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
			tmp[index++] = a[begin1++];
		else
			tmp[index++] = a[begin2++];
	}

	while (begin1 <= end1)
	{
		tmp[index++] = a[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[index++] = a[begin2++];
	}

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

/*
k用来表示每次k个元素归并
*/
void mergePass(int *arr, int k, int n, int *temp)
{
  int i = 0;
  //从前往后,将2个长度为k的子序列合并为1个
  while(i < n - 2*k + 1)
  {
    merge(arr, i, i + k - 1, i + 2*k - 1, temp);
    i += 2*k;
  }
  //合并区间[i, n - 1]有序的左半部分[i, i + k - 1]以及不及一个步长的右半部分[i + k, n - 1]
  if(i < n - k )
  {
    merge(arr, i, i + k - 1,n-1, temp);
  }
   
}

// 归并排序非递归版
void MergeSortNonR(int *arr,int length)
{
  int k = 1;
  int *temp = (int *)malloc(sizeof(int) * length);
  while(k < length)
  {
    mergePass(arr, k, length, temp);
    k *= 2;
  }
  free(temp);
}

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

// O(Max(N, 范围))
// O(N+范围) 时间复杂度
// O(范围) 空间复杂度
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* countArray = (int*)malloc(range*sizeof(int));
	memset(countArray, 0, sizeof(int)*range);
	//存放在相对位置,可以节省空间
	for (int i = 0; i < n; ++i)
	{
		countArray[a[i] - min]++;
	}
	//可能存在重复的数据,有几个存几个
	int index = 0;
	for (int i = 0; i < range; ++i)
	{	
		while (countArray[i]--)
		{
			a[index++] = i+min;
		}
	}
}

void TestCountSort()
{
	int a[] = { 3, 4, 6, 2, 8, 5, 2, 2, 9, 9, 1000000, 99999};
	CountSort(a, sizeof(a) / sizeof(int));
	PrintArray(a, sizeof(a) / sizeof(int));
}

void TestSortOP()
{
	const int n = 1000000;
	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);

	srand(time(0));
	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];
	}
	a8[n] = 100000000;

	size_t begin1 = clock();
	//InsertSort(a1, n);
	size_t end1 = clock();
	printf("%u\n", end1 - begin1);

	size_t begin2 = clock();
	ShellSort(a2, n);
	size_t end2 = clock();
	printf("%u\n", end2 - begin2);

	size_t begin3 = clock();
	//SelectSort(a3, n);
	size_t end3 = clock();
	printf("%u\n", end3 - begin3);

	size_t begin4 = clock();
	HeapSort(a4, n);
	size_t end4 = clock();
	printf("%u\n", end4 - begin4);
	
	size_t begin5 = clock();
	//BubbleSort(a5, n);
	size_t end5 = clock();
	printf("%u\n", end5 - begin5);

	size_t begin6 = clock();
	QuickSort(a6, 0, n-1);
	size_t end6 = clock();
	printf("%u\n", end6 - begin6);

	size_t begin7 = clock();
	MergeSort(a7, n);
	size_t end7 = clock();
	printf("%u\n", end7 - begin7);

	size_t begin8 = clock();
	CountSort(a8, n);
	size_t end8 = clock();
	printf("%u\n", end8 - begin8);
}

11.题目:

912. 排序数组

答案 

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

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

相关文章

【Git】篇一

文章目录 一、Git概述1、版本控制器的方式2、Git的工作流程图 二、Git的安装与常用命令1、Git环境安装2、Git环境基本配置3、获取本地仓库4、基础操作指令 三、分支 一、Git概述 开发中&#xff0c;代码备份、代码还原回滚、追溯、协同开发等场景必不可少&#xff0c;由此&…

特征可视化技术(CAM)

https://zhuanlan.zhihu.com/p/269702192 CAM技术可以帮助我们理解CNN在图像中寻找目标对象的过程&#xff0c;并且可以用于可视化CNN的中间层特征&#xff0c;以及对图像分类结果的解释和可视化。CAM技术的实现比较简单&#xff0c;可以使用常用的深度学习框架如PyTorch和Te…

【C++】模板进阶——非类型模板参数、模板特化、模板分离编译

目录 1.非类型模板参数array 2.模板的特化2.1概念2.2函数模板特化2.3类模板特化1.全特化2.偏特化3.类模板特化应用示例 3.模拟分离编译3.1什么是分离编译3.2模板的分离编译1.问题&#xff1a;2.原因3.解决方法 4.模板总结 1.非类型模板参数 模板参数分为类型形参 与 非类型形参…

重新思考无边界世界中的网络安全

©网络研究院 在一个越来越不是物理边界而是数字边界的世界里&#xff0c;全球网络安全事件的数量持续上升&#xff0c;公共部门机构面临的挑战也随之增加。 保护组成数据的利害关系比以往任何时候都更加重要。为了抵御这些数字威胁&#xff0c;政府机构正在采用零信任方…

sqlite基础

一.sqlite基础 1.下载与环境配置 从下载地址&#xff0c;点击我 这里下载适合你版本的压缩包 您需要下载 sqlite-tools-win32-*.zip 和 sqlite-dll-win32-*.zip 压缩文件。创建文件夹 C:\sqlite&#xff0c;并在此文件夹下解压上面两个压缩文件&#xff0c;将得到 sqlite3.d…

【模板方法设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

简介 模板方法模式&#xff08;Template Method Pattern&#xff09;也叫模板模式&#xff0c;是一种行为型模式。它定义了一个抽象公开类&#xff0c;包含基本的算法骨架&#xff0c;而将一些步骤延迟到子类中&#xff0c;模板方法使得子类可以不改变算法的结构&#xff0c;只…

ToLua框架

ToLua 是一个用于在 Unity 中为 Lua 提供 C# 语言绑定的框架。通过 ToLua&#xff0c;你可以方便地将 C# 代码暴露给 Lua 脚本&#xff0c;并在 Lua 脚本中调用 C# 类、方法和属性。 更新流程 原理&#xff1a;使用AssetBundle进行资源的更新&#xff0c;而由于lua运行时才编…

架构设计-分布式ID

一、 分布式ID基础 1.背景 1.为什么要引用分布式主键ID&#xff1f; 比如单机 MySQL 数据库&#xff0c;前期因为业务量不大&#xff0c;只是使用单个数据库存数据&#xff0c;后期发现业务量一下子就增长&#xff0c;单机 MySQL 已经不能满足于现在的数据量&#xff0c;单机…

【实战项目开发技术分享】常用的ROS工具与命令

常用的ROS工具介绍 作为机器人领域最为流行的开源框架之一,ROS(Robot Operating System)提供了丰富的工具来支持机器人的开发和部署。下面是一些常用的ROS工具及其功能的介绍: roscore:roscore是ROS的主要进程,它启动ROS Master节点并协调ROS系统中的所有进程。所有ROS节…

NEFU数据库基本操作实验总结

前言 SQL语言集数据定义、数据操纵、数据查询、数据控制功能于一体。 数据定义&#xff1a;create&#xff0c;drop&#xff0c;alter 数据操纵&#xff1a;增(insert into … )&#xff0c;删(delete from …)&#xff0c;改(update … set …) 数据查询&#xff1a;select 数…

如何在 Linux 环境下安装使用 pycharm?介绍一种快捷打开方式

之所以要出这个教程&#xff0c;是想介绍一种更快捷的打开方式。官网上的教程&#xff0c;每次打开都要切换到下载地址&#xff0c;然后输入 ./pycharm.sh 才能运行。 如图&#xff0c;在任意位置打开终端&#xff0c;敲快捷键pc就能打开 pycharm 怎么样&#xff0c;非常方便…

MYSQL进阶01

MYSQL进阶 存储引擎存储引擎的特性MyISAMInnoDBMEMORY 如何选择合适的引擎 存储引擎 MYSQL默认支持多种存储引擎&#xff0c;可以根据用户不同需求选择合适的储存引擎。MYSQL支持的存储引擎包括但不局限于以下几种&#xff08;MyISAM、InnoDB、MEMORY、MERGE…&#xff0c;创建…

【Leetcode -142.环形链表Ⅱ -143.重排链表】

Leetcode Leetcode -142.环形链表ⅡLeetcode - 143.重排链表 Leetcode -142.环形链表Ⅱ 题目&#xff1a;给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 …

CodeRush Ultimate Crack终极版

CodeRush Ultimate Crack终极版 CodeRush Ultimate通过提高生产力&#xff0c;同时消除侵蚀创造力的重复&#xff0c;帮助开发人员在更短的时间内提供更多高质量的功能。它可以帮助您在几秒钟内创建复杂的代码块&#xff0c;并立即扩展代码模板&#xff0c;并在您按逻辑键入、扩…

[架构之路-179]-《软考-系统分析师》-19- 系统可靠性分析与设计 - 故障模型、可靠性模型、可靠性分析

目录 前言&#xff1a; 1 9 . 1 系统可靠性概述 19.1.1 系统故障模型 1. 在信息系统中&#xff0c;故障或错误有如下儿种表现形式&#xff1a; 2. 故障的缘由 3. 故障模型 &#xff08;1&#xff09;逻辑电路级的故障 &#xff08;2&#xff09; 数据结构级的故障 &a…

spass modeler

课时1&#xff1a;SPSS Modeler 简介 本课时一共分为五个模块&#xff0c;分别是Modeler概述、工具安装、窗口说明以及功能介绍和应用案例。相信通过本课时内容的学习&#xff0c;大家将会对SPSS Modeler有个基础的了解. 在学习本节课内容之前&#xff0c;先来看看本节课我们究…

Wi-Fi (-6) 知识点整理

Wi-Fi - 6 知识点整理 2019年IEEE推出IEEE 802.11ax&#xff0c;WiFi联盟&#xff08;WFA&#xff09;称其为WiFi-6 Wi-Fi (Wireless Fidelity) 无线保真&#xff0c;无线兼容性认证 通信技术 商标 商业认证 技术联盟 Wi-Fi 网络基本要素 接入点&#xff08;Access Point&a…

前端存储二:indexedDB

indexedDB 特点&#xff1a;以域名纬度&#xff0c;浏览器大量结构化数据存储方案&#xff0c;运行在浏览器的非关系型数据库。 大小&#xff1a;不会小于 250MB&#xff0c;支持二进制存储。 接口&#xff1a;异步接口&#xff0c;支持事物机制 这里使用网页脚本生成&#x…

【五一创作】【Simulink】采用延时补偿的三相并网逆变器FCS-MPC

&#x1f449; 【Simulink】基于FCS-MPC的三相并网逆变器控制 上一篇博客介绍了FCS-MPC的基本操作&#xff0c;并且以三相并网逆变器为控制对象进行了Simulink仿真。 但实际仿真中没有考虑补偿延时。本篇博客将讨论为什么要考虑延时并进行补偿&#xff0c;最后对此仿真验证。 …