首页 > 其他分享 >八大排序(使用C语言)

八大排序(使用C语言)

时间:2024-06-06 21:28:56浏览次数:24  
标签:begin right end int 复杂度 C语言 八大 排序

完整代码链接:

诶嘿/DataStructure - 码云 - 开源中国 (gitee.com)

目录

一、排序的概念及应用:

1.排序的概念:

2.排序应用:

二、常见排序算法的实现: 

1 插入排序:

1.1 基本思想:

1.2 直接插入排序:

1.2.1 代码实现: 

1.2.2 测试:

1.2.3 时空复杂度:

1.3 希尔排序(缩小增量排序):

1.3.1 代码实现: 

1.3.2 测试: 

1.3.3 时空复杂度:

2 选择排序:

2.1 基本思想:

2.2 直接选择排序:

2.2.1 代码实现:

2.2.2 测试:

2.2.3 时空复杂度:  

2.3 堆排序: 

3 交换排序:

3.1 基本思想:

3.2 冒泡排序:

3.2.1 代码实现:

3.2.2 测试:

3.2.3 时空复杂度: 

3.3 快速排序:

3.3.1 基本思想:

3.3.2 递归版:

3.3.2.1 递归版基本框架:

3.3.2.2 左右指针法: 

 3.3.2.2.1 代码实现:

3.3.2.2.2 注意事项:

3.3.2.3 挖坑法:

3.3.2.3.1 代码实现:

 3.3.2.4 前后指针法:

 3.3.2.4.1 代码实现:

3.3.2.5 测试:

3.3.3 非递归版: 

3.3.3.1 代码实现:

 3.3.3.2 测试 :

3.3.4 时空复杂度: 

4 归并排序:

4.1 基本思想:

4.2 递归版:

4.2.1 代码实现: 

4.2.2 测试: 

4.3 非递归版:

4.3.1 代码实现: 

4.3.2 测试:

4.4 时空复杂度: 

5 计数排序:

5.1 基本思想:

5.2 代码实现:

5.3 测试:

5.4 时空复杂度: 

三、性能对比:

四、总结: 


一、排序的概念及应用:

1.排序的概念:

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

内部排序:数据元素全部放在内存中的排序。

外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求能在内外存之间移动数据的排序。

2.排序应用:

 3.常见排序算法:

二、常见排序算法的实现: 

Look me:我们这里统一排升序

1 插入排序:

1.1 基本思想:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

1.2 直接插入排序:

基本思路:当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与 array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移。

1.2.1 代码实现: 
//直接插入排序
void InsertSort(int* a, int n)
{
	assert(a);
	for (int i = 0;i < n - 1;i++)//注意i的边界
	{
		int end = i;
		int tmp = a[end + 1];
		while (end>=0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}
1.2.2 测试:

1.2.3 时空复杂度

①.时间复杂度:

由于第1次要跟0个数比较,第2次要跟1个数比较……第n次要跟n-1个数比较,所以,0+1+2+…n-1=\frac{n*(0+n-1)}{2}=\frac{n^2-n}{2},所以,时间复杂度为 O(N^{2})。

最好的情况:原数据有序或者接近有序,此时,时间复杂度为O(N)(每次进入while循环就break)。

最坏的情况:数组逆序或接近逆序。

②.空间复杂度:O(1)。

1.3 希尔排序(缩小增量排序):

背景:为了解决直接插入排序存在的问题(数组逆序或接近逆序时,时间复杂度为O(N^{2})),所以出现了希尔排序。

基本步骤

①.预排序:将间距为gap的值分为一组,让数组接近有序;

②.直接插入排序:当gap==1时,进行直接插入排序。

1.3.1 代码实现: 
void ShellSort(int* a, int n)
{
	assert(a);
	//1.gap>1相当于预排序,让数组接近有序
	//2.gap==1相当于直接插入排序,保证有序
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;//+1保证了gap最后一次一定是1,当gap==1时,会先执行一次循环。gap不止这一种取法,但是这个方法比较好
		for (int i = 0;i < n - gap;i++)//多组并排
		{
			//以gap为间距,执行单趟排序
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
		//PrintArray(a, n);//每次打印一下以gap为间距排序后的数组
	}
}
1.3.2 测试: 

1.3.3 时空复杂度:

①.时间复杂度:

希尔排序的时间复杂度不好计算,因为其时间复杂度受到gap的取值的影响,所以导致很难计算。其大概的时间复杂度为 O(N^{1.3}N^{2})。

②.空间复杂度:O(1)。

2 选择排序:

2.1 基本思想:

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

2.2 直接选择排序:

在原来的直接插入排序中,我们这里对其做了一个优化,时间效率增长了一倍。每次同时找到最大值与最小值,然后将最大值放在数组最后面,最小值放在数组最前面,缩小待排序区间后,重复上述步骤。

2.2.1 代码实现:
void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void SelectSort(int* a, int n)
{
	assert(a);
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini, maxi;
		mini = maxi = begin;//存储最小值与最大值的下标
		for (int i = begin + 1;i <= end;i++)
		{
			if (a[i] < a[mini])
			{
				mini = i;//更新最小值下标
			}
			if (a[i] > a[maxi])
			{
				maxi = i;//更新最大值下标
			}
		}
		Swap(&a[begin], &a[mini]);
		//如果maxi和begin在同一位置,则maxi的位置需要更改
		if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		//缩小区间
		begin++;
		end--;
	}
}

 

2.2.2 测试:

2.2.3 时空复杂度:  

①.时间复杂度:

第一次要比较n-2个数,第二次要比较n-4个数,……,所以其时间复杂度为 O(N^{2})。

②.空间复杂度:O(1)。

2.3 堆排序: 

这个我们之前讲了,可以看下面的链接。

二叉树的实现

3 交换排序:

3.1 基本思想:

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排 序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

3.2 冒泡排序:

基本思路:两两相比,前一个数大于后一个数就交换,第一次将最大的数放在最后,第二次将次大的放在倒数第二个位置,依次类推,直到只有一个数还有排序时。

3.2.1 代码实现:
void BubbleSort(int* a, int n)
{
	int end = n;
	while (end > 0)
	{
		int exchange = 0;
		for (int i = 1;i < end;i++)//单趟排序
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				exchange = 1;
			}
		}
		//如果一趟冒泡的过程中没有发生交换,则前部分已经有序,不需要再冒泡
		if (exchange = 0)
		{
			break;
		}
		end--;
	}
}
3.2.2 测试:

3.2.3 时空复杂度: 

①.时间复杂度:O(N^{2});

②.空间复杂度:O(1)。

3.3 快速排序:

3.3.1 基本思想

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后再在左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

3.3.2 递归版:
3.3.2.1 递归版基本框架:
void QuickSort(int* a, int left, int right)//right指向最后一个元素
{
	assert(a);
	if (left >= right)
		return;
	if ((right - left + 1) > 10)
	{
		int div = PartSort1(a, left, right);//左右指针法
        //int div = PartSort2(a, left, right);//挖坑法
        //int div = PartSort3(a, left, right);//前后指针法
		QuickSort(a, left, div - 1);//递归排左区间
		QuickSort(a, div + 1, right);//递归排右区间
	}
	else
	{
		//小于等于10个以内的区间,不再递归排序(小区间优化)
		InsertSort(a + left, right - left + 1);//小区间使用插入排序去排,不再使用快速排序的递归排,减少整体的递归次数
	}
}
3.3.2.2 左右指针法: 

基本步骤:

将最后一个位置的数据作为key值,用一个begin指针指向数组头,一个end指针指向数组尾,让begin先向右走,找到比key大的值停下来;再让end向左走,找到比key小的值停下来,然后交换begin与end所指向的值。重复begin与end操作,直到begin与end指向同一个位置,将该位置的值与key值交换,完成一次整体排序。接下来就是递归去排左右区间的数据。

 3.3.2.2.1 代码实现:
int GetMidIndex(int* a, int left, int right)//三数取中,保证不取到最大与最小
{
	int mid = (left + right) / 2;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])//a[left]<a[mid]<a[right]
			return mid;
		else if (a[left] > a[right])//a[right]<a[left]<a[mid]
			return left;
		else
			return right;//a[left]<a[right]<a[mid]
	}
	else//a[left]>a[mid]
	{
		if (a[mid] > a[right])//a[left]>a[mid]>a[right]
			return mid;
		else if (a[left] < a[right])//a[right]>a[left]>a[mid]
			return left;
		else
			return right;//a[left]>a[right]>a[mid]
	}
}
//前后指针法
int PartSort1(int* a, int begin, int end)
{
	int midIndex = GetMidIndex(a, begin, end);
	Swap(&a[end], &a[midIndex]);
	int keyIndex = end;
	while (begin < end)
	{
		while (begin < end && a[begin] <= a[keyIndex])//必须要有 begin < end,不然 begin 与 end 会错位
		{
			begin++;
		}
		while (begin < end && a[end] >= a[keyIndex])
		{
			end--;
		}
		Swap(&a[begin], &a[end]);
	}
	Swap(&a[begin], &a[keyIndex]);
	return begin;
}
3.3.2.2.2 注意事项:

①.不要直接选最左边或最右边的数作为key值。因为在极端情况下(数组有序或接近有序),如果key值每次都是最大(小)的数,快速排序的时间复杂度就会是O(N^{2})。

③.当我们选择最右边值作为key值时,要让begin先走;同样地,当我们选择最左边值作为key值时,要让end先走。因为begin先走一定能保证相遇时所在位置的值一定比key要大(要么begin从左边与end相遇,要么end从右边与begin相遇,相遇点的位置一定在begin位置处,而begin是去找大于key的数),然后与key交换才不会出错(以升序为例)。

3.3.2.3 挖坑法:

基本步骤:

利用GetMidIndex()函数找到key,将其作为坑,然后begin去找比key值大的位置,把原来的坑给填上,将begin位置作为新的坑;然后让end去找比key值小的位置,再把原来的坑给填上,将end位置作为新的坑。重复上述步骤,直到begin与end指向同一个位置,再把key给填进去。接下来就是去递归排左右区间了。

3.3.2.3.1 代码实现:
int PartSort2(int* a, int begin, int end)
{
	int midIndex = GetMidIndex(a, begin, end);
	Swap(&a[end], &a[midIndex]);
	int key = a[end];//坑(坑就是指该位置的值被拿走了,可以被新的值覆盖)
	while (begin < end)
	{
		while (begin < end && a[begin] <= key)
		{
			begin++;
		}
		//左边找到比key大的填到右边的坑,begin位置形成新的坑
		a[end] = a[begin];
		while (begin < end && a[end] >= key)
		{
			end--;
		}
		//右边找到比key小的值填到左边的坑,end位置形成新的坑
		a[begin] = a[end];
	}
	a[begin] = key;
}
 3.3.2.4 前后指针法:

基本步骤:

同样的,先找到key值。让一个cur指针指向数组第一个位置,prev指针指向数组第一个位置的前一个位置,当cur所指向的位置小于key时,prev向后走一步,然后交换cur与prev所指向的值;如果cur所指向的值大于key,就自加一步,prev不动。重复上述步骤,当cur走到最后一个位置,让prev再向后走一步,交换key与prev所指向位置的值,这样就实现了把小的翻到左边,大的推到右边。然后就是递归去排左右区间。

 3.3.2.4.1 代码实现:
int PartSort3(int* a, int left, int right)
{
	int midIndex = GetMidIndex(a, left, right);//7
	Swap(&a[right], &a[midIndex]);
	int keyIndex = right;

	int cur = left;
	int prev = left - 1;
	while (cur < right)
	{
		if (a[cur] < a[keyIndex] && ++prev != cur)
			Swap(&a[cur], &a[prev]);
		
		cur++;
	}
	Swap(&a[++prev], &a[keyIndex]);
	return prev;
}
3.3.2.5 测试:

3.3.3 非递归版: 

对于递归实现快速排序,如果需要排的数很多,可能会存在栈溢出问题(栈帧的深度太深,导致栈里面装不下了)

所以,我们这里需要使用一个栈(数据结构)来实现非递归 ,其本质就是用栈来保存要排序数组所在的区间,再在这个区间里面去排一下序(随便使用递归版里面的三种方法之一)。

3.3.3.1 代码实现:
void QuickSortNonR(int* a, int left, int right)
{
	assert(a);
	Stack st;
	StackInit(&st);
	//将要排序的数组下标压入栈内
	StackPush(&st, right);
	StackPush(&st, left);
	while (!StackEmpty(&st))
	{
		int begin = StackTop(&st);
		StackPop(&st);
		int end = StackTop(&st);
		StackPop(&st);
		//[begin,end]
		int div = PartSort3(a, begin, end);
		//[begin,div-1] div [div+1,end]
		if (div + 1 < end)//当数组里面值得个数>1
		{
			StackPush(&st, end);
			StackPush(&st, div+1);
		}
		if (begin < div - 1)
		{
			StackPush(&st, div - 1);
			StackPush(&st, begin);
		}
	}
	StackDestory(&st);
}

我们这里也可以加上小区间优化:

void QuickSortNonR(int* a, int left, int right)
{
	assert(a);
	if (right - left + 1 > 10)
	{
		Stack st;
		StackInit(&st);
		//将要排序的数组下标压入栈内
		StackPush(&st, right);
		StackPush(&st, left);
		while (!StackEmpty(&st))
		{
			int begin = StackTop(&st);
			StackPop(&st);
			int end = StackTop(&st);
			StackPop(&st);
			//[begin,end]
			int div = PartSort3(a, begin, end);
			//[begin,div-1] div [div+1,end]
			if (div + 1 < end)//当数组里面值得个数>1
			{
				if (end - div > 10)//end-(div+1)+1
				{
					StackPush(&st, end);
					StackPush(&st, div + 1);
				}
				else//小区间优化
				{
					InsertSort(a, end - div);
				}
			}
			if (begin < div - 1)
			{
				if (div - begin > 10)//div-1-begin+1
				{
					StackPush(&st, div - 1);
					StackPush(&st, begin);
				}
				else//小区间优化
				{
					InsertSort(a, div - begin);
				}

			}
		}
		StackDestory(&st);
	}
	else//小区间优化
	{
		InsertSort(a, right - left + 1);
	}
}
 3.3.3.2 测试 :

3.3.4 时空复杂度: 

①. 时间复杂度:O(NlogN);

②.空间复杂度:

因为在递归期间,使用栈帧也是会消耗空间的(但是递归回来,原来的空间又会被销毁,所以原来的空间可以重复利用),所以其空间复杂度是依据递归的深度决定的,因为这里深度为logn,所以空间复杂度为O(logN)

4 归并排序:

4.1 基本思想:

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列。即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

相信屏幕前的你看了这个题会更容易理解归并排序的思想:

合并两个有序数组

4.2 递归版:

基本步骤:

①.将原数组递归分解成一个个元素;

②.利用合并两个有序数组思想,合并分解后的数组。

4.2.1 代码实现: 
//合并
void MergeArr(int* a, int begin1, int end1, int begin2, int end2, int* tmp)
{
	int left = begin1, right = end2;
	int index = begin1;
	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++];
	//把归并好的tmp的数据再拷贝到原数组
	for (int i = left;i <= right;i++)
		a[i] = tmp[i];
}
void _MergeSort(int* a, int left, int right, int* 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);
	//归并[left,mid] [mid+1,right] 有序
	MergeArr(a, left, mid, mid + 1, right, tmp);
}
void MergeSort(int* a, int n)
{
	assert(a);
	int* tmp = malloc(sizeof(a[0]) * n);//创建辅助空间
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
}

4.2.2 测试: 

4.3 非递归版:

基本思路:

同样的,我们也要像递归版一样分解与归并数组。我们这里可以用一个gap变量来分解数组,在分解后的数组里面进行归并,利用gap的变化实现不同组的归并,直到gap==n时(可能不会到n,取决于左右子序列所在区间的范围,不能是gap>n/2时结束,因为不能保证左子序列与右子序列的区间长度是一样的),结束归并。

4.3.1 代码实现: 
//合并
void MergeArr(int* a, int begin1, int end1, int begin2, int end2, int* tmp)
{
	int left = begin1, right = end2;
	int index = begin1;
	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++];
	//把归并好的tmp的数据再拷贝到原数组
	for (int i = left;i <= right;i++)
		a[i] = tmp[i];
}
void MergeSortNonR(int* a, int n)
{
	assert(a);
	int* tmp = malloc(sizeof(a[0]) * n);
	int gap = 1;
	while (gap < n)//不能是gap<=n/2,左右区间不一定均分
	{
		for (int i = 0;i < n;i += 2 * gap)
		{
			//[i,i+gap) [i+gap,i*2gap)
			//[i,i+gap-1] [i+gap,i*2gap-1]
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
             //数组的长度不一定都是2^n
			//1.合并时只有第一组,第二组不存在,就不需要合并
			if (begin2 >= n)
				break;
			//2.合并时第二组只有部分数据,需要修正end2边界
			if (end2 >= n)
				end2 = n - 1;
			MergeArr(a, begin1, end1, begin2, end2, tmp);
		}
		gap *= 2;
	}
	free(tmp);
}
4.3.2 测试:

4.4 时空复杂度: 

①.时间复杂度:O(NlogN);

②.空间复杂度:O(N)。

5 计数排序:

5.1 基本思想:

计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。

基本步骤

①. 统计相同元素出现次数;

②. 根据统计的结果将序列回收到原来的序列中。

5.2 代码实现:

void CountSort(int* a, int n)
{
	assert(a);
	int min = a[0];
	int max = a[0];
	for (int i = 1;i < n;i++)
	{
		if (a[i] > max)
			max = a[i];
		if (a[i] < min)
			min = a[i];
	}
	int range = max - min + 1;
	int* countArr = (int*)malloc(sizeof(a[0]) * range);
	memset(countArr, 0, sizeof(a[0]) * range);
	//统计次数
	for (int i = 0;i < n;i++)
	{
		countArr[a[i] - min]++;
	}
	//排序
	int index = 0;
	for (int j = 0;j < range;j++)
	{
		while (countArr[j]--)
		{
			a[index++] = j + min;
		}
	}
	free(countArr);
}

5.3 测试:

5.4 时空复杂度: 

①.时间复杂度:计数排序的时间复杂度与空间复杂度会依据数据范围集中程度而变化,所以其时间复杂度为O(MAX(N,范围));

②.空间复杂度:O(范围)。

三、性能对比:

四、总结: 

标签:begin,right,end,int,复杂度,C语言,八大,排序
From: https://blog.csdn.net/weixin_74385491/article/details/139225131

相关文章

  • C语言通过socket实现TCP客户端
    socket概念​ 从wiki上了解,socket这个词追溯到1971年RFC147的发布。​ 目前我的理解:常用于指操作系统提供的API,该API允许使用TCP、UDP进行连接,但不仅限于TCP、UDP协议。实现目的利用系统提供函数接口,通过C语言实现对TCP服务器(IP地址)的连接,以及收发数据。实现......
  • C语言关于预处理的基础介绍
    一:预定义符号    在c语言中有一些预定义的符号,这些符号已经定义好了,用户不需要再次定义只需要使用即可。 __FILE__:显示当前进行编译的源文件__LINE__:显示当前代码行号__DATE__:显示当前文件被编译的日期__TMIE__:显示当前文件被编译的时间__STDC__:查看当前编译......
  • 快速排序(排序中篇)
    1.快速排序的概念及实现2.快速排序的时间复杂度3.优化快速排序4.关于快速排序的细节5.总代码1.快速排序的概念及实现1.1快速排序的概念快速排序的单趟是选一个基准值,然后遍历数组的内容把比基准值大的放右边,比基准值小的放在左边,下面的动图可以简单了解是这么排序的。......
  • C语言:详解gcc驱动程序完成编译、汇编、链接的过程
    相关阅读C语言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm=1001.2014.3001.5482    gcc是一个命令,严格意义上说,它只是一个驱动程序,而不是一个编译器。gcc负责调用GNU工具链中的预处理器、编译器、汇编器、链接器等工具,通过传递不同的选项给g......
  • 【C语言】指针(4)
    一、回顾 在这之前,我们学习了很多关于指针的内容,我们先在这里简单的回顾一下。1、一级指针int*p;  --整形指针-指向整形的指针 char*p;...void*p;......2、二级指针int**p; char**p;...3、数组指针--指向数组的指针int(*p)[];intmain(){......
  • C语言杂谈:函数栈帧,函数调用时到底发生了什么
            我们都知道在调用函数时,要为函数在栈上开辟空间,函数后续内容都会在栈帧空间中保存,如非静态局部变量,返回值等。这段空间就叫栈帧。    当函数调用,就会开辟栈帧空间,函数返回时,栈帧空间就会被释放。这里的释放并非清空,而是让其无效化,可以后续的使用。1,......
  • 一文带你搞定八大排序算法
    目录前言排序的时间复杂度、稳定性插入排序直接插入排序 时间复杂度希尔排序 时间复杂度选择排序选择排序 时间复杂度堆排序交换排序冒泡排序 时间复杂度快速排序左右指针法 优化:三数取中 优化:小区间优化挖坑法前后指针法快速排序非递归法 时间复......
  • 冒泡排序、插入排序、快速排序
    三种排序:冒泡排序、插入排序、快速排序规则:冒泡排序:每一轮循环后,最大的一个数被交换到末尾,因此,下一轮循环就可以“刨除”最后的数,每一轮循环都比上一轮循环的结束位置靠前一位。插入排序:将待排序数组分为已排序和未排序两部分,初始已排序部分只包含第一个元素。然后,从第二个元素......
  • 001__C语言程序入门
    一、第一个程序:helloworld配置部署好vsCode之后,就可以直接在上面写代码了,新建一个新的C程序文件,向屏幕输出一串字符“HelloWorld!”下面,从整体上来分析一下这个最简单的C语言程序,将这个最简程序的各个部分剖析清楚,明白我们写下的每一个字符的具体含义。二、C语言的基本结......
  • 三种常见的排序方法
    一.比较交换排序法方法:将第一个元素的数据与其后的每个数据进行比较。如果不符合比较类型,则交换数据。例如:将一组数据15,8,4,13,6,10,17,1按照由小到大的顺序递增排列     分析:第一轮arr[0]分别与后面的数据比较,互换数值,将最小的数安排在下标是0的数组元素中。 ......