数的排序

296 阅读5分钟

​这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

 

  我在初次接触算法时学到了几种数的排序方法想在此介绍给大家,大部分算法来自《啊哈!算法》第一章节。

  先来介绍一种比较简单的方法

桶排序(真正的桶排序更加复杂,这个是简化版)

把数字看做小红旗,建立一个数组来存放数字。

如图(图来自《啊哈!算法》,下同)

把数字按下标存放在数组中然后按顺序输出,

例如,a[0]没有小红旗所以不输出,a[2]有一次所以输出一次,a[5]有两个小红旗所以输出两次。

如代码

​
​
#include <stdio.h>
int main()
{
	int number[10] = { 0 };//对0到9之间的整数排序
	int n,i;
	for ( i=1; i <= 5; i++)//循环读入五个数
	{
		scanf_s("%d", &n);
		number[n]++;
	}
	for ( i = 0; i <= 10; i++)//判断number[0]~number[9]
	{
		for (int j = 1; j <= number[i]; j++)//看出现了几次
		{
			printf("%d", i);
		}
	}
	return 0;
}

这个方法很简单,但是也有很大的局限性

1、如果范围在0~100那么就要需要101个桶也就是说要定义一个元素为101个的数组。如果数据大了对内存的要求太大了。

2、目前这个方法对于浮点数类型数据有很大限制,不适合浮点数的排序。

然后再介绍一个耳熟能详的方法

冒泡排序

冒泡排序的基本思想是:比较两个相邻的元素,如果它们的顺序是错误的,就把它们交换过来。

如图

像鱼缸冒泡一样一个一个的把数字归位。

如代码

#include <stdio.h>
int main()
{
	int number[10] = {1,5,6,7,8,9,8,4,5,6};//对0到9之间的整数排序
	int n,i;
	for (i = 1; i <= 9; i++)//n个数只要比较n-1次就可以了
	{
		for (n = 0; n < 10 - i; n++)//从0开始比较,之所以是要小于10-i是因为每经过一次就会确定
		{                          //一个位置所以需要比较的位置是0~n-i
			if (number[n]>=number[n+1])
			{
				int max = number[n];
				number[n] = number[n + 1];
				number[n + 1] = max;
			}
		}
	}
	for (i = 0; i <= 9; i++)
	{
		printf("%d ", number[i]);
	}
	return 0;
}

冒泡排序的核心部分是双重嵌套循环。

一个循环用来代表比较次数

一个循环用来数组之间的比较

这里在插一嘴,一种算法的好坏取决于使用内存的多少和时间复杂度的大小。

那么上面的冒泡排序还有什么优化方法吗?

其实还是有的,你们想过吗?冒泡排序就一定要把每一个数都排列一次吗?如果数组里有已经排好了的数字的话,我们要怎么办?

*其实很简单: *只要增加一个开关量就可以了

如:

#include <stdio.h>
int main()
{
	int number[10] = {1,5,6,7,8,9,8,4,5,6};//对0到9之间的整数排序
	int n,i;
	int flag=1;
	for (i = 1; i <= 9; i++)//n个数只要比较n-1次就可以了
	{
		for (n = 0; n < 10 - i; n++)//从0开始比较,之所以是要小于10-i是因为每经过一次就会确定
		{                          //一个位置所以需要比较的位置是0~n-i
			if (number[n]>=number[n+1])
			{
				int max = number[n];
				number[n] = number[n + 1];
				number[n + 1] = max;
				flag = 0;//关上开关
			}
			if (flag == 1)
			{
				break;//如果已经排序好那么就会跳出循环
			}
		}
	}
	for (i = 0; i <= 9; i++)
	{
		printf("%d ", number[i]);
	}
	return 0;
}

这段代码比上一段进行了判断是否已经排序好的操作。

上面介绍的两种方法各有优点和缺点,比如桶排序需要更大的内存,冒泡排序的时间复杂性更高

下面介绍一种更加有优势的排序方法

最常用的排序——快速排序

快速排序需要找到一个基准数,把比基准数小的放右边,比基准数大的放左边。(当然左右可以互换)

比如

2 ,5,6 ,8,9,7,4,3,1

把6作为基准数比6大的放左边,比6小的放右边

2,5,4,3,1,6,8,9,7

方法为:分别从初始序列“2 ,5,6 ,8,9,7,4,3,1"两端开始找起

下面我直接把书上的内容给挂出来

如图

在左右设置2个坐标来分别负责找到比基准数大和小的数,注意是是右边先出发

如果“i”找到了比基准数小的的时候停下,“j”找到比基准数大的时候停下,然后两个数互换

如图

这样就完成了一次交换,注意我举的例子和图中并不一样。

*我举的例子第一次交换完后应该是: *2 ,5,6 ,1,9,7,4,3,8

直到两个坐标相遇则把相遇的坐标时的数和基准数互换

最后应该为:2,5,1,4,3,6,7,9,8

这样就把数列分成了以6位边界的两个数列2,5,1,4和7,9,8然后在用同样的方法把两个数列排序直到最后分不出新的数列为止。

用代码来表示就是

#include <stdio.h>
int number[100], n;
void test_1(int left,int right)//用了一个递归算法
{
	int i, j, t, temp;//temp基准数
	if (left > right)
		return;
	temp = number[left];
	i = left;
	j = right;
	while (i != j)
	{
		while (number[j] >= temp && i < j)//**先从右向左找**
			j--;
		while (number[i] <= temp && i < j)
			i++;
		if (i < j)
		{
			t = number[i];
			number[i] = number[j];
			number[j] = t;
		}
	}
	//最终将基准数归位
	number[left] = number[i];
	number[i] = temp;

	test_1(left, i - 1);//递归
	test_1(i + 1, right);//递归
}
int main()
{
	int i, j, t;
	scanf_s("%d", &n);
	for (i = 0; i < n; i++)
	{
		scanf_s("%d", &number[i]);
	}
	test_1(0, n-1);
	for (i = 0; i < n; i++)
	{
		printf("%d ", number[i]);
	}
	return 0;
}

快速排序是基于二分思想的一种排序方法,它的特点是每次交换是跳跃式的,相对于冒泡排序来说

选择排序(简单选择排序)

下面介绍的排序方法是我老师在课堂上教给我的方法

例如有下列一些数:

2 5 4 1 6 7   要把它们按从小到大排序

首先把2用“k”标记,把接下来的数用“j”标记

如果遇到了比2小的数把它和2互换到第一位,直到最后一位数,然后在从下一位开始排序

如代码

#include<stdio.h>
int main()
{
	int number[5] = { 2,5,4,8,9, };
	int k, j;
	for (k = 0; k <= 3; k++)
	{
		for (j = k + 1; j < 5; j++)
		{
			if(number[k]>number[j])
			{
				int t = number[k];
				number[k] = number[j];
				number[j] = number[k];
			}
		}
	}
	for (k = 0; k < 5; k++)
	{
		printf("%d ", number[k]);
	}
	return 0;
}

最后在介绍一种排序方法

插入排序

#include<stdio.h>
int number[6] = { 6,1,5,8,4,3 };
void test_1()
{
	int len = 6;
	int i, j, tmp;
	for (i = 1; i < len; i++)
	{
		tmp = number[i];//从1开始插入
		for (j = i - 1; j >= 0;j--)
		{
			if (tmp < number[j])//如果前面的数大于tmp将他们向后移动一位
			{
				number[j + 1] = number[j];
			}
			else
			{
				break;
			}
		}
		number[j + 1] = tmp;//因为for循环会使得j多去减去1所以要加1。
	}
}
int main()
{
	test_1();
	for (int a = 0; a < 6; a++)
	{
		printf("%d ", number[a]);
	}
	return 0;
}

注意:插入排序是从后面开始的

以上就是我想介绍的几种排序方法,如果存在错误欢迎指正━(`∀´)ノ亻!