排序算法之基本几种排序方法

目录

排序算法

1.什么是排序算法。

2.基本都排序算法有哪些

3.怎么衡量排序算法的优劣

4.冒泡排序思想和代码

4.1 普通冒泡排序的思想和代码

4.2 冒泡排序升级版的思想和代码

5.结语


排序算法

1.什么是排序算法。

当你有一堆数据的时候,看着他们杂乱无章,无序的时候是不是看着特别不爽。是不是特想看着它们是从小到大,或者从大到小排列的,看着就舒服多了。还有哦,排序可不止是让你看着舒服,还有一部分是查找。在一堆数据中查找是否存在一个数据,如果是一堆杂乱无章的数据,我们就只能一个个比较,是否是你要的那个数据,最差的情况,要把全部的数据比较一次,这样就会浪费很多时间和空间。那如果一组数据是有序的呢。是不是可以通过查找算法来省很多的时间空间,查找算法都是基于数据是有序的情况下,比如说,折半查找,比例查找,斐波那契查找。这些能提高查找效率,但是都是基于数据有序。所以我们迫切的需要把无序的数据变成有序。这样的算法就叫做排序算法。


2.基本都排序算法有哪些

基本都排序算法有冒泡排序、选择排序、插入排序、希尔排序、堆排序、归并排序等等等等。


3.怎么衡量排序算法的优劣

衡量一个算法的优劣度有三个方面:时间复杂度和空间复杂度,稳定性。这两个复杂度是什么意思呢?时间复杂度就是一个算法的执行时间。而空间复杂度就是算法在运行过程中临时占用存储空间的度量。我们通常用O()来比较复杂程度,比如O(N)<O(N*logN)<O(N^2)。

在排序算法中我们往往关注的是时间的多少。而决定一个算法时间的多少主要来源于循环的次数。如果我们在一个算法中循环了N次那么时间复杂度就是O(N)如果循环了N^2次那么就是O(N^2)。有时候我们会有循环次数是N^2-N次的情况那是不是时间复杂度就是O(N^2-N)呢?其实不是的,因为当数据量很大的时候N相对于N^2那消耗的时间就太少太少,我们可以忽略不计。而当数据量小的时候时间相差也不会太大,所以我们舍弃增长慢的那个项

循环次数越少,时间复杂度越低,算法越好。

稳定性是什么? 稳定性是当你有相同的数据后,这几个相同的数据的相对位置是不变化的,这个算法就是稳定的,会发生变化就是不稳定的。什么意思呢?

6 4 2 6 这里有五个数据进行排序之后是2 3 4 6 6 如果是这样的,带下划线的6还是在没有下划线的前面,尽管这两个6都是一样的,但相对位置不变,那么就是稳定的,

如果是2 3 4 6 6这样的那么就是不稳定的。

越稳定算法越好

其实算法没有绝对的好坏,主要是取决于你想要哪方面,比如你想要占内存少的,那你就选择空间复杂度低的,如果你想要运算时间短,反应快,那你就选择时间复杂度低的,如果你想要一个稳定的算法,那你就选择比较稳定的。算法各有优劣,看你需要哪方面。

4.冒泡排序思想和代码

4.1 普通冒泡排序的思想和代码

冒泡排序的思想就是用第一个数据和第二个数据做比较,如果第一个比第二个大,那么就交换,交换完了就是第二个比第一个大了,如果第二个比第一个本来就大,那么就不用换。然后再比较第二个和第三个,第二个大,那就交换。这样又是第三个大了。以此往复到最后一个,这样是不是最后一个就是这组数据中最大的数了。这样就选出一个最大的数了,所以我们只需要选出第二个,第三个最大的数就可以了。因此我们n个数据只需要循环n-1次就可以排完所有的数据,是不是想问为什么是n-1,因为当你前n-1个数据都排列好的之后,最后的一个数据就必定是最小的,不用排列。

所以代码如下

//冒泡排序
void bubbleSort(int data[], int n)
{
	int cmpNum = 0;//比较次数
	int swapNum = 0;//交换次数
	printf("————————冒泡排序————————\n");
	//排序前打印数据
	printArr(data, n);
	for (int i = 0; i < n - 1; ++i)
	{
		for (int j = 0; j < n - 1 - i; ++j)
		{
			++cmpNum;
			if (data[j] > data[j + 1])
			{
				//交换
				swap(data, j, j + 1);
				++swapNum;
			}
		}
	}
	//排序完打印数据
	printArr(data, n);
	printf(" 比较了%d 次,交换了%d 次\n", cmpNum, swapNum);
	printf("————————冒泡排序————————\n");
}

其中参数

data[]:待排序的数组

n: 待排序的数据个数

为了更好的打印数组和交换数据,写了两个函数printArr()和swap()

函数定义代码如下:

//打印数组
void printArr(int data[], int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d  ", data[i]);
	}
	putchar('\n');
}
//交换数组的两个数据
void swap(int data[], int i, int j)
{
	int temp;
	temp = data[i];
	data[i] = data[j];
	data[j] = temp;
}

int cmpNum = 0;//比较次数
 int swapNum = 0;//交换次数

定义这两个变量是为了比较算法的优劣

由上面的思路就很容易写出代码了

第一层循环是总共要走n-1趟,从第一个走到最后一个的次数。

第二层循环是每一趟要比较的次数,第一趟要从a[0]到a[n - 1]个,第二趟要去除第一次排好的数据所以到a[n-1-i]。

冒泡排序的时间复杂度O(N^2)

空间复杂度O(1)注(O(1)说明空间和循环次数无关)

稳定性 稳定

就如此冒泡排序就好了,看看执行过程吧

4.2 冒泡排序升级版的思想和代码

我们现在了解了冒泡排序,是不是该想一想能不能改进一下,因为这个冒泡排序不管我们的数据是怎样的,它都是要循环(N-1)*N/2=N+(N-1)+(N-2).....+1。但是如果给的数据就是一个有序的数据比如a[]={0,1,2,3,4,5,6,7,8,9},就这个组数据,用上面的冒泡排序我们是不是还是要循环45次,而数据本来就是有序的,我们不想让他比较。想一想,我们能不能让他判断了数据已经变成了有序,然后直接退出循环,结束就行了。但什么时候才算是有序呢。。想一想,当然是循环了一趟,发现都没有交换过,那不就是有序的吗。所以我们能对上面的冒泡的代码进行改进,加一个标志位,标志着目前的数据是不是有序,有序就直接退出。直接看代码吧。

//冒泡排序升级,对于已经排好的,立即退出排序
void bubleSortPlus(int data[], int n)
{
	int flag = 0;
	int cmpNum = 0;//比较次数
	int swapNum = 0;//交换次数
	printf("————————冒泡排序升级版————————\n");
	//排序前打印数据
	printArr(data, n);
	for (int i = 0; i < n - 1; ++i)
	{
		flag = 0;
		for (int j = 0; j < n - 1 - i; ++j)
		{
			++cmpNum;
			if (data[j] > data[j + 1])
			{
				//交换
				swap(data, j, j + 1);
				++swapNum;
				flag = 1;
			}
		}
		//一轮下来没有交换一个元素,说明已经排好了
		if (flag == 0)
		{
			break;
		}
	}
	//排序后打印数据
	printArr(data, n);
	printf(" 比较了%d 次,交换了%d 次\n", cmpNum, swapNum);
	printf("————————冒泡排序升级版————————\n");
}

参数和普通的冒泡排序一样,只是增加了一个标志flag=1时说明前一趟交换过,数据还不是有序的,需要继续排序。

看下运行结果

 虽然目前的比较次数和普通的冒泡是一样的。这是因为这组数据是到最后一趟才变成有序的,要是我一开始就用一个有序的数据去排序呢,那么它是不是只要比较一趟就行,我们看结果。

看看普通的冒泡是怎样的

 和有序和无序是比较同样的次数。

5.结语

所以升级版在数据会提前有序的情况下,明显优于普通的冒泡,就算最差的情况也是和普通的冒泡比较同样的次数。

冒泡排序分享完成了。接下来还有选择排序,插入排序,希尔排序,堆排序,持续更新敬请期待。

下一节——选择排序在这里

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行风~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值