这是我参与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;
}
注意:插入排序是从后面开始的
以上就是我想介绍的几种排序方法,如果存在错误欢迎指正━(`∀´)ノ亻!