常见的五种排序,冒泡排序,选择排序,插入排序,并归排序,快速排序

8 篇文章 0 订阅
4 篇文章 0 订阅

冒泡排序

冒泡排序介绍:
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地跑过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小)那么它就会按照大到小的排序方式来。它必须要把算所有的元素重复地进行跑一遍,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

冒泡排序算法的原理如下:
1,比较相邻的元素。如果第一个比第二个大,就交换他们两个,如果不是相等的就跳过比下面的元素 ,这样依次的循环下去 直到所有的元素都比较完成才结束。
2,针对所有的元素重复以上的步骤,除了最后一个。
3,持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

在这里插入图片描述

冒泡排序代码如下:

//冒泡排序
#include<stdio.h>
int main(void)
{
	int Array[10] = { 5,3,7,2,8,2,8,22,7 ,6 };
	int Num = 10, temp;
	bool Sorted = true;
	while (Sorted)
	{
		Sorted = false;       //假设没有交换
		for (int i = 0; i < Num - 1; i++)
		{
			if (Array[i + 1] > Array[i])
			{
				Sorted = true;              //如果有交换重新把Sorted设置为 true
				temp = Array[i + 1];
				Array[i + 1] = Array[i];
				Array[i] = temp;
			}
		}
		Num--;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d  ", Array[i]);
	}
}

选择排序

选择排序介绍:
选择排序是通过每一趟排序过程中从待排序记录中选择出关键字最小(大)的记录,将其依次放在数据表的最前或最后端的方法来实现整个数据表的有序排列。

选择排序算法的原理如下:
第一趟排序在所有待排序的n个记录中选出关键字最小的记录,将它与数据表中的第一个记录交换位置,使关键字最小的记录处于数据表的最前端;第二趟在剩下的n-1个记录中再选出关键字最小的记录,将其与数据表中的第二个记录交换位置,使关键字次小的记录处于数据表的第二个位置;重复这样的操作,依次选出数据表中关键字第三小、第四小…的元素,将它们分别换到数据表的第三、第四…个位置上。排序共进行n-1趟,最终可实现数据表的排列。
在这里插入图片描述

选择排序代码如下:

//选择排序
#include<stdio.h>
int main(void)
{
	int Array[10] = { 5,4,7,3,8,3,8,21,87,24 };

	int temp, min;

	for (int i = 0; i < 10; i++)
	{
		min = i;
		for (int j = i + 1; j < 10; j++)
		{
			if (Array[min] < Array[j])         
				min = j;
		}
		if (min != i)                     
		{
			temp = Array[min];
			Array[min] = Array[i];
			Array[i] = temp;
		}
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d   ", Array[i]);
	}
}


冒泡排序和选择排序的区别

区别在于:在交换的方式上

冒泡算法,每次比较如果发现较小的元素在,就交换两个相邻的元素。

而选择排序算法的改进在于:先并不急于调换位置,先从A[1]开始逐个检查,看哪个数最小就记下该数所在的位置P,等一躺扫描完毕,再把A[P]和A[1]对调,这时A[1]到A[10]中最小的数据就换到了最前面的位置。

所以,选择排序每扫描一遍数组,只需要一次真正的交换,而冒泡可能需要很多次。比较的次数一样的。

例如:1 2 3 4我们分别用a[0],a[1],a[2],a[3]存储。假设从大到小排序

选择排序,是a[0]和a[1],a[2],a[3]依次比较,遇到小的就交换,这样一次下来,最大的被保存在了a[0].下次排序就从a[1]开始重复以上步骤。

冒泡排序,是a[0]和a[1]比较,小的就交换。然后a[1]和a[2]比较,小的交换。然后a[2]和a[3]比较小的就交换。这样一次下来,最大的被保存在a[0]。下次排序从a[1]开始重复以上步骤。

虽然差不多,但是请注意:两者的比较方法是右差别的,一个事依次比下来,一个是俩俩比较。

冒泡排序的基本思想是将数组中的每个相邻元素进行两两比较,按照小元素在前(或大元素在前)的原则确定是否进行交换。这样每一轮执行之后,最大(或最小)的元素就会被交换到了最后一位,同样的过程会依次进行,直到所有元素都被排列成预期的顺序为止。这个过程是不是像是水中的起泡一个个冒起来的过程.

选择排序,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。

插入排序

插入排序简介:
插入排序是将数组的第一个数认为是有序数组,从后往前(从前往后)扫描该有序数组,把数组中其余n-1个数,根据数值的大小,插入到有序数组中,直至数组中的所有数有序排列为止。这样的话,n个元素需要进行n-1趟排序!!!

举个例子:4个数字4,6,7,5进行从大到小的排序。前插排序法具体过程如下:
把第一个数4插入到空的有序数组中的第一个位置上,得到新数字序列4;

第一趟:从后往前扫描有序数组,将第二个数字6和有序数组中的4进行比较,6大于4,此时将4后移一个位置。此时已经扫描完有序数组中的数,将6插入到4的前面(有序数组的第一个位置),得到新数字序列6,4;

第二趟:从后往前扫描有序数组,先将第三个数字7和有序数组中的4进行比较,7大于4,此时将4后移一个位置;再将7和有序数组中的6进行比较,7大于6,此时将6后移一个位置。此时已经扫描完有序数组中的数,将7插入到6的前面(有序数组的第一个位置),得到新数字序列7,6,4;

第三趟:从后往前扫描有序数组,先将第四个数字5和有序数组中的4进行比较,5大于4,此时将4后移一个位置;再将5和有序数组中的6进行比较,5小于6,由于有序数组就按照从大到小排列的,此时直接把5插入到4的前面即可!不需要再和7进行比较!最后,得到新数字序列7,6,5,4;

插入排序算法的原理如下:
直接插入排序的基本操作是将一个记录插入到已经排好的有序表中,从而得到一个新的、记录数增1的有序表。对于给定的一组记录,初始时假定第一个记录自成一个有序序列,其余记录为无序序列。接着从第二个记录开始,按照记录的大小依次将当前处理的记录插入到其之前的有序序列中,直到最后一个记录插到有序序列中为止。
在这里插入图片描述

插入排序代码如下:

//插入排序
#include<stdio.h>
int main()
{
	int array[10] = { 5,1,4,2,4,3,3,5,76,76 };
	for (int i = 1; i < 10; i++)
	{
		int j = i - 1;
		int temp = array[i];
		while (j >= 0 && temp < array[j])        //如果temp小于array[j]一直交换
		{
			array[j + 1] = array[j];
			j--;            //递减
		}
		array[j + 1] = temp; //将array[i]与array[m+1]互换
	}
	//输出排序结果
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", array[i]);
	}
	return 0;
}

并归排序

并归排序简介
归并排序(Merge Sort)就是利用归并的思想实现的排序方法。它的原理是假设初始序列有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到⌈n/2⌉个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。

并归排序算法的原理如下:`

设两个有序的子序列(相当于输入序列)放在同一序列中相邻的位置上:array[low…m],array[m + 1…high],先将它们合并到一个局部的暂存序列 temp (相当于输出序列)中,待合并完成后将 temp 复制回 array[low…high]中,从而完成排序。

在具体的合并过程中,设置 i,j 和 p 三个指针,其初值分别指向这三个记录区的起始位置。合并时依次比较 array[i] 和 array[j] 的关键字,取关键字较小(或较大)的记录复制到 temp[p] 中,然后将被复制记录的指针 i 或 j 加 1,以及指向复制位置的指针 p加 1。重复这一过程直至两个输入的子序列有一个已全部复制完毕(不妨称其为空),此时将另一非空的子序列中剩余记录依次复制到 array 中即可。

若将两个有序表合并成一个有序表,称为2 路归并。

在这里插入图片描述

并归排序代码如下:

//并归排序
#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
int Array[10] = { 4,33,5,-3,4,6,44,6,-7,8 };

void merge(int lo, int mi, int hi)    //[lo, mi)和[mi, hi)各自有序,lo < mi < hi
{
	int i = 0, j = 0, k = 0;         //计数器
	int* A = Array + lo;		 //合并后的有序向量A[0, hi - lo) = Array[lo, hi),就地
	int lb = mi - lo;        //mi前面不包括mi
	int lc = hi - mi;        //mi后面的包括mi
	int* B = new int[lb];	 //前子向量B[0, lb) <-- Array[lo, mi)

	for (int i = 0; i < lb; i++) B[i] = A[i];     //复制自A的前缀

	
	int* C = Array + mi;     //后子向量C[0, lc) = Array[mi, hi),就地

	while ((j < lb) && (k < lc))					  //反复地比较B、C的首元素
		A[i++] = (B[j] <= C[k]) ? B[j++] : C[k++]; //将更小者归入A中

	while (j < lb) //若C先耗尽,则
		A[i++] = B[j++]; //将B残余的后缀归入A中

	while (k < lc) //若C先耗尽,则
		A[i++] = C[k++]; //将C残余的后缀归入A中

	delete[] B; //释放临时空间:mergeSort()过程中,如何避免此类反复的new/delete?
}

void mergeSort(int lo, int hi)
{
	if (hi - lo < 2)                 //递归终止条件
		return;
	int mi = (lo + hi) / 2;

	mergeSort(lo, mi);        //分别排序
	mergeSort(mi, hi);
	merge(lo, mi, hi);        //归并
}

int main(void)
{
	mergeSort(0, 10);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", Array[i]);
	}
	return 0;
}


快速排序

快速排序简介

快速排序,听这个名字就能想到它排序速度快,它是一种原地排序。其基本思想是随机找出一个数(通常就拿数组第一个数据就行),把它插入一个位置,使得它左边的数都比它小,它右边的数据都比它大,这样就将一个数组分成了两个子数组,然后再按照同样的方法把子数组再分成更小的子数组,直到不能分解为止。 它也是分治思想的一个经典实验(归并排序也是)

快速排序原理:

排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。

其思想是:先选一个“标尺”,用它把整个队列过一遍筛子,以保证:其左边的元素都不大于它,其右边的元素都不小于它。这样,排序问题就被分割为两个子区间。再分别对子区间排序就可以了。
在这里插入图片描述

快速排序代码如下:

//快速排序
#include<stdio.h>
int FindPos(int* AA, int lo, int hi)
{
	int val=AA[lo];           //等于需要排序区间的第一个元素
	while (lo < hi)
	{
		while (lo < hi && AA[hi] >= val)        //如果AA[hi]大于val hi的值递减
		{
			--hi;
		}
		AA[lo] = AA[hi];        
		while (lo < hi && AA[lo] <= val)       //如果AA[lo]小于于val hi的值递增
		{
			++lo;
		}
		AA[hi] = AA[lo];
	}
	AA[lo] = val;
	return hi;
}

void QuickSort(int* AA, int lo, int hi)
{
	int Pos;
	if (lo < hi)        //递归条件
	{
		Pos = FindPos(AA, lo, hi);
		QuickSort(AA, lo, Pos - 1);
		QuickSort(AA, Pos + 1, hi);
	}
}

int main(void)
{
	int array[6] = { 3,-3,5,2,7,3 };
	QuickSort(array, 0, 5);
	for (int i = 0; i < 6; i++)
	{
		printf("%d  ", array[i]);
	}
}

上述五种排序的测试结果

代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
int Array [10] =  { 4,3,6,36,7,64,7,23,67,2 };
int Array2[10] = { 4,3,6,36,7,64,7,23,67,2 };
int Array3[10] = { 4,3,6,36,7,64,7,23,67,2 };
int Array4[10] = { 4,3,6,36,7,64,7,23,67,2 };
int Array5[10] = { 4,3,6,36,7,64,7,23,67,2 };
void Select_Sort(int AA[], int Num)
{
	cout << "原: ";
	copy(Array, Array + 10, ostream_iterator<int>(cout, "  "));
	cout << endl;
	bool Sorted = true;
	int mi, Temp;
	int Count = 0;
	for (int i = 0; i < Num; i++)
	{
		mi = i;
		for (int j = i + 1; j < Num; j++)
		{
			Count++;
			if (AA[mi] < AA[j])
				mi = j;
		}
		if (mi != i)
		{
			Temp = AA[mi];
			AA[mi] = AA[i];
			AA[i] = Temp;
		}
		
	}
	printf("Select_sort******  %d  *******\n", Count);
	
	copy(AA, AA + 10, ostream_iterator<int>(cout, "  "));
	cout << endl << endl << endl;
}

void Bubble_Sort(int AA[], int Num)
{
	cout << "原: ";
	copy(Array2, Array2 + 10, ostream_iterator<int>(cout, "  "));
	cout << endl;
	int Temp, Count = 0;
	bool Sorted = true;
	while (Sorted)
	{
		Sorted = false;
		for (int i = 1; i < Num; i++)
		{
			Count++;
			if (AA[i] > AA[i - 1])
			{
				Sorted = true;
				Temp = AA[i];
				AA[i] = AA[i - 1];
				AA[i - 1] = Temp;
			}
		}
		Num--;
	}
	printf("Bubble_sort******  %d  *******\n", Count);
	copy(AA, AA + 10, ostream_iterator<int>(cout, "  "));
	cout << endl << endl << endl;
}
void Insert_Sort(int AA[], int Num)
{
	cout << "原: ";
	copy(Array3, Array3 + 10, ostream_iterator<int>(cout, "  "));
	cout << endl;
	int Count = 0;
	for (int i = 1; i < Num; i++)
	{
		int j = i - 1;
		int Temp = AA[i];
		while (j >= 0 && AA[j] < Temp)
		{
			Count++;
			AA[j + 1] = AA[j];
			j--;
		}
		AA[j + 1] = Temp;
	}

	printf("Insert_sort******  %d  *******\n", Count);
	copy(AA, AA + 10, ostream_iterator<int>(cout, "  "));
	cout << endl << endl << endl;
}

//记录并归排序时间复杂度的变量
int Count = 0;

void Merge(int lo,int mi, int hi)
{
	int *AA = Array4 + lo;
	int Ib = mi - lo;
	int Ic = hi - mi;
	int* BB = new int[Ib];
	int* CC = Array4 + mi;
	int i = 0, j = 0, k = 0;
	for (int i = 0; i < Ib; i++)
	{
		BB[i] = AA[i];
		Count++;
	}

	while (j < Ib && k < Ic)
	{
		AA[i++] = BB[j] > CC[k] ? BB[j++] : CC[k++];
		Count++;
	}
	while (j < Ib)
	{
		AA[i++] = BB[j++];
		Count++;
	}
	while (k < Ic)
	{
		AA[i++] = CC[k++];
		Count++;
	}
		
}

void Merge_Sort(int lo,int hi)
{
	if (hi - lo < 2)
		return;
	int mi = (lo + hi) >> 1;
	Merge_Sort(lo, mi);
	Merge_Sort(mi, hi);
	Merge(lo, mi, hi);
}

//记录快速排序时间复杂度的变量

int Count2 = 0;

int FindPos(int* AA, int lo, int hi)
{
	int Val = AA[lo];
	while (lo < hi)
	{
		Count2++;
		while (lo < hi && AA[hi] <= Val)
		{
			hi--;
			Count2++;
		}
		AA[lo] = AA[hi];
		while (lo < hi && AA[lo] >= Val)
		{
			lo++;
			Count2++;
		}
		AA[hi] = AA[lo];
	}
	AA[lo] = Val;
	return lo;
}

void Quick_Sort(int* AA, int lo, int hi)
{
	int Pos;
	if (lo < hi)
	{
		Pos = FindPos(Array5, lo, hi);
		Quick_Sort(AA, lo, Pos - 1);
		Quick_Sort(AA, Pos + 1, hi);
	}
}

int main(void)
{
	Select_Sort(Array, 10);
	Bubble_Sort(Array2, 10);
	Insert_Sort(Array3, 10);
	
	cout << "原: ";
	copy(Array4, Array4 + 10, ostream_iterator<int>(cout, "  "));
	cout << endl;
	Merge_Sort(0, 10);
	printf("Merge_sort******  %d  *******\n", Count);
	copy(Array4, Array4 + 10, ostream_iterator<int>(cout, "  "));
	cout << endl << endl << endl;

	cout << "原: ";
	copy(Array5, Array5 + 10, ostream_iterator<int>(cout, "  "));
	cout << endl;
	Quick_Sort(Array5, 0, 9);
	printf("Quick_sort******  %d  *******\n", Count2);
	copy(Array5, Array5 + 10, ostream_iterator<int>(cout, "  "));
	cout << endl << endl << endl;
}

测试结果如图:
在这里插入图片描述
测试结果为: 选择排序和冒泡排序的时间复杂度相同 大于插入排序和选择排序,小于并归排序。
总结:在该测试中插入排序法效率最高,并归排序法效率最低。

本篇到此结束。如果您发现本篇中有什么错误的地方麻烦您在评论区留言,谢谢!
如果遇到什么问题欢迎大家进群讨论或者加我qq
群内有各种学习资料,欢迎大家一起来学习!
本人qq:846581636
qq学习群:759252814
期待你的关注
感谢大家的支持,谢谢!

  • 16
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值