【数据结构初阶第十九节】八大排序系列(下篇)—[详细动态图解+代码解析]

news2025/3/16 10:36:40

hello,好久不见! 云边有个稻草人-CSDN博客

上篇内容,回顾一下吧【数据结构初阶第十八节】八大排序系列(上篇)—[详细动态图解+代码解析]-CSDN博客

今天我们来学习下篇

目录

(2)快速排序

【挖坑法】

—思路

—思路图解 

—代码

【lomuto前后指针法】

—思路

—思路图解 

—代码

—效果展示

—快速排序特性总结

【非递归版本快排】

—思路

—思路图解

—代码

4.归并排序

—大致思路

—大致思路图解

—代码

—归并排序特性总结

—效果展示

5.测试代码:排序性能对比

6.非比较排序—计数排序

—图解

—代码

—计数排序的特性

—效果展示

三、排序算法复杂度及稳定性分析

稳定性

四、两节课代码汇总

Stack.h

sort.h

Stack.c

sort.c

test.c

未完待续——

   ———————————————《剧终The End》———————————————


续接上篇,正文开始——

(2)快速排序

【挖坑法】
—思路
创建左右指针。⾸先从右向左找出⽐基准⼩的数据,找到后⽴即放⼊左边坑中,当前位置变为新的"坑",然后从左向右找出⽐基准⼤的数据,找到后⽴即放⼊右边坑中,当前位置变为新的"坑",结束循环后将最开始存储的分界值放⼊当前的"坑"中,返回当前"坑"下标(即分界值下标)

—思路图解 
—代码
//挖坑法
int _QuickSort(int* arr, int left, int right)
{
	int hole = left;
	int key = arr[left];
	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;
}

//快排
void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	//1.找基准值
	int key = _QuickSort(arr,left,right);
	//2.左子序列进行排序
	QuickSort(arr, left, key - 1);
	//3.右子序列进行排序
	QuickSort(arr, key + 1, right);
}
【lomuto前后指针法】
—思路
创建前后指针,从左往右找⽐基准值⼩的进⾏交换,使得⼩的都排在基准值的左边。
—思路图解 

—代码
//lomuto前后指针
int _QuickSort(int* arr, int left, int right)
{
	int key = left;
	int prev = left, cur = left + 1;
	while (cur <= right)
	{
		if (arr[cur] < arr[key] && ++prev != cur)//这里的等号加不加都一样,
                                                 //对于全是重复的数据时间复杂度很高
		{
			Swap(&arr[cur], &arr[prev]);
		}
		cur++;
	}
	Swap(&arr[prev], &arr[key]);
	return prev;
}

//快排
void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	//1.找基准值
	int key = _QuickSort(arr,left,right);
	//2.左子序列进行排序
	QuickSort(arr, left, key - 1);
	//3.右子序列进行排序
	QuickSort(arr, key + 1, right);
}
—效果展示

—快速排序特性总结
1. 时间复杂度: O ( nlogn )
2. 空间复杂度: O ( logn )

【非递归版本快排】
—思路
非递归版本的快速排序需要借助数据结构:栈。
主要思路就是利用循环来模拟递归。将区间进行入栈,两次取栈顶数据(不要忘记出栈,取栈顶数据前判断栈是否为空)作为一个区间,在这个区间内通过前面学到的某种方法得到基准值,再根据基准值得到新的左右区间再入栈,入栈前要判断要入栈的区间是否是有效区间,再两次取栈顶数据循环前面操作。
—思路图解

—代码

这里我们采用lomuto方法进行取基准值

//非递归版本的快排
void QuickSortNonR(int* arr, int left, int right)
{
	ST st;
	STInit(&st);
	//首先将left和right进行入栈
	StackPush(&st, right);
	StackPush(&st, left);

	while (!StackEmpty(&st))
	{
		//取栈顶元素--取两次
		int begin = StackTop(&st);
		StackPop(&st);

		int end = StackTop(&st);
		StackPop(&st);

		//找基准值
		int keyi = begin;
		int cur = begin + 1;
		int prev = begin;

		while (cur <= end)
		{
			if (arr[cur] < arr[keyi] && ++prev != cur)
			{
				Swap(&arr[prev], &arr[cur]);
			}
			cur++;
		}
		Swap(&arr[prev], &arr[keyi]);

		keyi = prev;//找到了基准值
		//根据基准值再去找新的左右区间再入栈
		//左区间:[begin,keyi-1]
		//右区间:[keyi+1,end]
		if (keyi + 1 < end)
		{
			StackPush(&st, end);
			StackPush(&st, keyi + 1);
		}
		if (keyi - 1 > begin)
		{
			StackPush(&st, keyi - 1);
			StackPush(&st, begin);
		}
	}
	STDestroy(&st);
}

4.归并排序

—大致思路

利用二叉树递归的思想先将数组进行递归分解,直到每个区间分的只有一个数据此时不能再分,分解之后就是合并,注意合并的是一个数组里面两个区间里的数据并不是真的新的两个数组,合并的方法是利用我们前面学到的算法题—合并两个数组;我们是将合并之后有序的数据先存放到一个新创建的tmp数组里面,再将tmp里面的数据拷贝给原数组arr,这样方便操作一些;就这样在不断递归的过程中完成排序操作。

—大致思路图解

—代码
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);

	//合并
	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++];
		}
	}

	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);
}
—归并排序特性总结
1. 时间复杂度: O ( nlogn )
2. 空间复杂度: O ( n )
—效果展示

对于同样的10W个数据,不同的排序分别用了多久 

5.测试代码:排序性能对比

前面我们讲过的,这里再发一下,看一下代码就可以明白其中的道理。

// 测试排序的性能对⽐
void TestOP()
{
	srand(time(0));
	const 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);
	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];
	}

	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();

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

	int begin3 = clock();
	SelectSort(a3, N);
	int end3 = clock();

	int begin4 = clock();
	HeapSort(a4, N);
	int end4 = clock();

	int begin5 = clock();
	QuickSortNonR(a5, 0, N - 1);
	int end5 = clock();

	int begin6 = clock();
	MergeSort(a6, N);
	int end6 = clock();

	int begin7 = clock();
	BubbleSort(a7, N);
	int end7 = clock();

	printf("InsertSort:%d\n", end1 - begin1);
	printf("ShellSort:%d\n", end2 - begin2);
	printf("SelectSort:%d\n", end3 - begin3);
	printf("HeapSort:%d\n", end4 - begin4);
	printf("QuickSort:%d\n", end5 - begin5);
	printf("MergeSort:%d\n", end6 - begin6);
	printf("BubbleSort:%d\n", end7 - begin7);

	free(a1);
	free(a2);
	free(a3);
	free(a4);
	free(a5);
	free(a6);
	free(a7);
}

int main()
{
	TestOP();
	return 0;
}

6.非比较排序—计数排序

计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。
操作步骤:
1)统计相同元素出现次数
2)根据统计的结果将序列回收到原来的序列中
—图解

—代码
//计数排序
void CountSort(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 file!");
		exit(1);
	}

	//初始化range数组里面的数据都为0
	memset(count, 0, range * sizeof(int));

	//统计原数组中每个数据出现的次数,将次数存放对应的在count数组里面
	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;
		}
	}
}
—计数排序的特性
计数排序在数据范围集中时,效率很高,但是适⽤范围及场景有限,只适用于整数排序,无法对小数进行排序。
时间复杂度: O(N + range) —遍历一遍 count 数组,里面的 while 循环执行了N次,就是有多少个数据就执行多少次
空间复杂度: O(range) —开辟了range个空间
稳定性:稳定
—效果展示

这么强 ?!!!

0 ?!真假的

三、排序算法复杂度及稳定性分析

稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。(就是相同的数据排序之后的相对次序保持不变)
自己把前面的所有排序算法都理解透彻并能自己实现出来,自己理解下面的表格就会很轻松,不然都忘记了就会很痛苦。。。对于稳定性自己找出实例后独立分析

四、两节课代码汇总

Stack.h

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

//定义栈的结构
typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int capacity;  //栈的容量
	int top;       //栈顶
}ST;

//初始化
void STInit(ST* ps);

//销毁
void STDestroy(ST* ps);

//入数据
void StackPush(ST* ps, STDataType x);

//出数据
void StackPop(ST* st);

//取栈顶元素
STDataType StackTop(ST* ps);

//判空
bool StackEmpty(ST* ps);

//获取栈中有效的数据个数
int STsize(ST* ps);

sort.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<memory.h>

void Print(int* arr, int n);
void BubbleSort(int* arr, int n);
void HeapSort(int* arr, int n);
void InsertSort(int* arr, int n);
void ShellSort(int* arr, int n);
void SelectSort(int* arr, int n);
void QuickSort(int* arr, int left, int right);

//非递归版本的快排
void QuickSortNonR(int* arr, int left, int right);

//归并排序
void MergeSort(int* arr, int n);

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

Stack.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"

//初始化
void STInit(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;  //此时栈为空,栈顶=栈底
}

//销毁
void STDestroy(ST* ps)
{
	assert(ps);
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

//入数据
void StackPush(ST* ps, STDataType x)
{
	assert(ps);

	//判断空间是否足够
	if (ps->capacity == ps->top)
	{
		//申请空间
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc file!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}

//出数据
void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}

//判空
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

//取栈顶元素
STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

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

//获取栈中有效的数据个数
int STsize(ST* ps)
{
	assert(ps);
	return ps->top;
}

sort.c

#include"sort.h"
#include"Stack.h"

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

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 AdjustDown(int* arr, int parent, int 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[parent], &arr[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//堆排序
void HeapSort(int* arr, int n)
{
	//向下调整算法建堆
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(arr, i, n);
	}

	//堆排序
	int end = n - 1;
	while (end > 0)
	{
		//end指向的是最后一个数据
		Swap(&arr[0], &arr[end]);
		//有效的数据个数减了1
		AdjustDown(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)
		{
			if (arr[end] > tmp)
			{
				arr[end + 1] = arr[end];
				end--;//--是为了让tmp与区间前面的元素进行挨个比较,最后找到合适的位置
			}
			else
			{
				break;
			}
		}
		//此时end可能等于-1,或者是因为end指向的元素 < tmp,此时我们还没有进行最后的赋值,
		//这时我们都要把tmp里面的数据赋值给arr[end+1]
		arr[end + 1] = tmp;
	}
}

//希尔排序
void ShellSort(int* arr, int n)
{
	int gap = n;
	//用来控制gap,当gap==1时就是直接插入排序
	while (gap > 1)//不能等于1,等于1的话最后会死循环
	{
		gap = gap / 3 + 1;//保证最后一次gap一定为1,/3,是为了让每组数据个数较恰当
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = end;
					end-=gap; 
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

直接选择排序
//void SelectSort(int* arr, int n)
//{
//	for (int i = 0; i < n; i++)
//	{
//		int mini = i;
//		//找后面区间里最小值的下标
//		for (int j = i; j < n; j++)
//		{
//			if (arr[j] < arr[mini])
//			{
//				mini = j;
//			}
//		}
//		Swap(&arr[i], &arr[mini]);
//	}
//}


//直接插入排序
void SelectSort(int* arr, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini = begin, maxi = begin;
		//在后面区间内找maxi,mini
		for (int j = begin+1; j <= end; j++)
		{
			if (arr[j] < arr[mini])
			{
				mini = j;
			}
			if (arr[j] > arr[maxi])
			{
				maxi = j;
			}
		}
		if (maxi == begin)
		{
			maxi = mini;
		}

		Swap(&arr[begin], &arr[mini]);
		Swap(&arr[end], &arr[maxi]);
		begin++;
		end--;
	}
}

Hoare版本找基准值
//int _QuickSort(int* arr, int left, int right)
//{
//	int key = left;
//	left++;
//	while (left <= right)
//	{
//		//找比基准值大的
//		while (left <= right && arr[left] < arr[key])
//		{
//			left++;
//		}
//		//找比基准值小的
//		while (left <= right && arr[right] > arr[key])
//		{
//			right--;
//		}
//		if (left <= right)
//		{
//			Swap(&arr[right--], &arr[left++]);
//		}
//	}
//	//将right指向的数据和key指向的数据进行交换
//	Swap(&arr[key], &arr[right]);
//
//	return right;
//}

挖坑法
//int _QuickSort(int* arr, int left, int right)
//{
//	int hole = left;
//	int key = arr[left];
//	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;
//}

//lomuto前后指针
int _QuickSort(int* arr, int left, int right)
{
	int key = left;
	int prev = left, cur = left + 1;
	while (cur <= right)
	{
		if (arr[cur] < arr[key] && ++prev != cur)
		{
			Swap(&arr[cur], &arr[prev]);
		}
		cur++;
	}
	Swap(&arr[prev], &arr[key]);
	return prev;
}

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

//非递归版本的快排
void QuickSortNonR(int* arr, int left, int right)
{
	ST st;
	STInit(&st);
	//首先将left和right进行入栈
	StackPush(&st, right);
	StackPush(&st, left);

	while (!StackEmpty(&st))
	{
		//取栈顶元素--取两次
		int begin = StackTop(&st);
		StackPop(&st);

		int end = StackTop(&st);
		StackPop(&st);

		//找基准值
		int keyi = begin;
		int cur = begin + 1;
		int prev = begin;

		while (cur <= end)
		{
			if (arr[cur] < arr[keyi] && ++prev != cur)
			{
				Swap(&arr[prev], &arr[cur]);
			}
			cur++;
		}
		Swap(&arr[prev], &arr[keyi]);

		keyi = prev;//找到了基准值
		//根据基准值再去找新的左右区间再入栈
		//左区间:[begin,keyi-1]
		//右区间:[keyi+1,end]
		if (keyi + 1 < end)
		{
			StackPush(&st, end);
			StackPush(&st, keyi + 1);
		}
		if (keyi - 1 > begin)
		{
			StackPush(&st, keyi - 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);

	//合并
	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++];
		}
	}

	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);
}

//计数排序
void CountSort(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 file!");
		exit(1);
	}

	//初始化range数组里面的数据都为0
	memset(count, 0, range * sizeof(int));

	//统计原数组中每个数据出现的次数,将次数存放对应的在count数组里面
	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;
		}
	}
}

test.c

#include"sort.h"

void test()
{
	int arr[] = { 5,3,9,6,2,4,7,1,8 };
	int n = sizeof(arr) / sizeof(int);
	printf("排序前:");
	Print(arr, n);

	/*InsertSort(arr, n);*/
	/*BubbleSort(arr, n);*/
	CountSort(arr,n);

	printf("排序后:");
	Print(arr, n);

}

// 测试排序的性能对⽐
void TestOP()
{
	srand(time(0));
	const 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);

	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];
	}

	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();

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

	int begin3 = clock();
	SelectSort(a3, N);
	int end3 = clock();

	int begin4 = clock();
	HeapSort(a4, N);
	int end4 = clock();

	int begin5 = clock();
	QuickSort(a5, 0, N - 1);
	int end5 = clock();

	int begin6 = clock();
	MergeSort(a6, N);
	int end6 = clock();

	int begin7 = clock();
	BubbleSort(a7, N);
	int end7 = clock();

	int begin8 = clock();
	CountSort(a8, N);
	int end8 = clock();

	printf("InsertSort:%d\n", end1 - begin1);
	printf("ShellSort:%d\n", end2 - begin2);
	printf("SelectSort:%d\n", end3 - begin3);
	printf("HeapSort:%d\n", end4 - begin4);
	printf("QuickSort:%d\n", end5 - begin5);
	printf("MergeSort:%d\n", end6 - begin6);
	printf("BubbleSort:%d\n", end7 - begin7);
	printf("CountSort:%d\n", end8 - begin8);

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

int main()
{
	//TestOP();
	test();
	return 0;
}

数据结构初阶的所有内容就更新完了,后面还有一些加餐内容。下面我们正式开启C++和Linux的内容。。。

完—— 

未完待续——

   ———————————————《剧终The End》———————————————

 剧终_TRK_高音质在线试听_剧终歌词|歌曲下载_酷狗音乐

(放学骑车的路上随机播放到了这首歌,感觉挺应景的,就它喽。看到一条评论:比起剧终,我更喜欢未完待续)  

(你相信星座吗,我一开始不相信,后来发现真的有点像,说实话现在也不咋相信,但是这是巧合吗还是,疑惑)

至此结束!

我是云边有个稻草人。。。

期待与你的下一次相遇,再见!

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

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

相关文章

定制开发开源 AI 智能名片 S2B2C 商城小程序源码在小程序直播营销中的应用与价值

摘要&#xff1a; 本文主要探讨了定制开发开源 AI 智能名片 S2B2C 商城小程序源码在小程序直播营销中的应用与价值。首先详细阐述了小程序直播的基本概念、特点、发展历程及营销意义&#xff0c;包括其便捷性、广泛的受众连接能力以及对企业推广的重要作用。接着深入剖析了定制…

蓝桥杯Python赛道备赛——Day3:排序算法(二)(归并排序、堆排序、桶排序)

本博客是蓝桥杯备赛系列中排序算法的第二期&#xff0c;包括&#xff1a;归并排序、堆排序和桶排序。每一个算法都在给出概念解释的同时&#xff0c;给出了示例代码&#xff0c;以供低年级师弟师妹们学习和练习。 由于本期的三个算法的复杂度相对来说要高于上一期的三个算法&am…

Type-C:智能家居的电力革命与空间美学重构

在万物互联的时代浪潮中&#xff0c;家居空间正经历着从功能容器到智慧终端的蜕变。当意大利设计师安东尼奥奇特里奥提出"消失的设计"理念二十年后&#xff0c;Type-C充电技术正以润物无声的方式重塑着现代家居的形态与内核&#xff0c;开启了一场静默的居住革命。 【…

第十五届蓝桥杯C/C++组:宝石组合题目(从小学奥数到编程题详解)

这道题目真的一看就不好做&#xff0c;如果直接暴力去做百分之90必挂掉&#xff0c;那么这道题目到底应该怎么去做呢&#xff1f;这我们就得从小学奥数开始聊了。&#xff08;闲话&#xff1a;自从开始蓝桥杯备赛后&#xff0c;每天都在被小学奥数震惊&#xff0c;为什么我小的…

ECharts中Map(地图)样式配置、渐变色生成

前言 ECharts是我们常用的图表控件&#xff0c;功能特别强大&#xff0c;每次使用都要查API比较繁琐&#xff0c;这里就记录开发中常用的配置。 官网&#xff1a;https://echarts.apache.org/handbook/zh/get-started 配置项&#xff1a;https://echarts.apache.org/zh/opti…

MySQL | MySQL表的增删改查(CRUD)

目录 前言&#xff1a;什么是 CRUD ?一、Creat 新增1.1 语法1.2 示例1.2.1 单行数据全列插入1.2.2 单行数据指定列插入1.2.3 多行数据指定列插入 二、Retrieve 检索2.1 语法2.2 示例2.2.1 全列查询2.2.2 指定列查询2.2.3 查询字段为表达式2.2.4 结果去重查询2.2.5 where条件查…

电子电气架构 --- 分布到集中的动カ系统及基于域控制器的架构

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

基于SpringBoot的“考研互助平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“考研互助平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 局部E-R图 系统首页界面 系统注册…

基于javaweb的SpringBoot足球俱乐部管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

DQN 玩 2048 实战|第一期!搭建游戏环境(附 PyGame 可视化源码)

视频讲解&#xff1a; DQN 玩 2048 实战&#xff5c;第一期&#xff01;搭建游戏环境&#xff08;附 PyGame 可视化源码&#xff09; 代码仓库&#xff1a;GitHub - LitchiCheng/DRL-learning: 深度强化学习 2048游戏介绍&#xff0c;引用维基百科 《2048》在44的网格上进行。…

高频面试题(含笔试高频算法整理)基本总结回顾24

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

第八节:红黑树(初阶)

【本节要点】 红黑树概念红黑树性质红黑树结点定义红黑树结构红黑树插入操作的分析 一、红黑树的概念与性质 1.1 红黑树的概念 红黑树 &#xff0c;是一种 二叉搜索树 &#xff0c;但 在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是 Red和 Black 。 通过对 任何…

Webpack vs Rollup vs Parcel:构建工具深度对比

文章目录 1. 核心特性对比1.1 功能定位1.2 技术架构对比 2. 配置与使用2.1 Webpack 配置示例2.2 Rollup 配置示例2.3 Parcel 使用示例 3. 性能对比3.1 构建速度3.2 输出质量 4. 生态系统4.1 插件生态4.2 学习曲线 5. 适用场景分析5.1 Webpack 适用场景5.2 Rollup 适用场景5.3 P…

Centos7使用docker搭建redis集群

前置准备&#xff1a; Centos7安装docker就不多说了… 本次目的是搭建3主3从&#xff08;当然你也可以按需扩展&#xff09;准备三台服务器&#xff0c;假定IP分别为&#xff1a;192.168.75.128、192.168.75.129、192.168.75.130安装 redis&#xff1a; #拉取redis docker p…

数字孪生像魔镜,映照出无限可能的未来

在当今科技飞速发展的时代&#xff0c;数字孪生作为一项极具潜力的前沿技术&#xff0c;正逐渐崭露头角&#xff0c;成为众多领域关注的焦点。它犹如一面神奇的魔镜&#xff0c;以数字化的方式精准映照出现实世界中的各种实体与系统&#xff0c;为我们开启了一扇通往无限可能未…

前端知识点---原型-原型链(javascript)

文章目录 原型原型链:实际应用面试题回答 原型 原型:每个函数都有prototype属性 称之为原型 因为这个属性的值是个对象&#xff0c;也称为原型对象 只有函数才有prototype属性 作用: 1.存放一些属性和方法 2.在Javascript中实现继承 const arr new Array(1, 2, 3, 4) con…

数据类设计_图片类设计之6_混合图形类设计(前端架构)

前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 接续上一篇,讨论混合图形类设计 方法论-现在能做什么 这段属于聊天内容---有句话是这么说的&#xff1a;不要只埋头拉车&#xff0c;还要抬头看路。写代码也是…

2024年12月CCF-GESP编程能力等级认证C++编程一级真题解析

一级真题的难度: ‌ CCF-GESP编程能力等级认证C++编程一级真题的难度适中‌。这些真题主要考察的是C++编程的基础知识、基本语法以及简单的算法逻辑。从搜索结果中可以看到,真题内容包括了选择题、编程题等题型,涉及的内容如C++表达式的计算、基本输入输出语句的理解…

尤瓦尔·诺亚·赫拉利(Yuval Noah Harari)作品和思想深度报告

尤瓦尔诺亚赫拉利&#xff08;Yuval Noah Harari&#xff09;作品和思想深度报告 引言 尤瓦尔诺亚赫拉利&#xff08;Yuval Noah Harari&#xff09;是当今最具影响力的公众知识分子之一 ynharari.com 。作为一名历史学家和哲学家&#xff0c;他以宏大的视角和清晰生动的语言…

JConsole:JDK性能监控利器之JConsole的使用说明与案例实践

&#x1fa81;&#x1f341; 希望本文能给您带来帮助&#xff0c;如果有任何问题&#xff0c;欢迎批评指正&#xff01;&#x1f405;&#x1f43e;&#x1f341;&#x1f425; 文章目录 一、背景二、JConsole的启动与连接2.1 JConsole的启动2.2 进程连接2.2.1 本地进程连接2.2…