C日记——基本的排序算法

来源:互联网 发布:2016华为云计算大会 编辑:程序博客网 时间:2024/05/16 00:45

语法是语言的特色,而算法却是灵魂
算法不分语言
入门的算法要数排序算法

今天的算法讲解将以c语言为例子将以下几个排序算法

1. 桶排序
2. 插入排序
3. 冒泡排序
4. 快速排序

首先给大家介绍一个最简单粗暴的排序算法

桶排序

桶排序要先知道要排序的数的范围
然后要这么多的桶去装这些可能出现数的次数
桶排序

//这里的范围是0~999
int b[1000];

这个数组就是用来装出现次数的
然后输入数字,然后这个相应的桶的次数就加1
输出时遍历全部桶,然后桶的数字是几就输出几次这个数字

代码如下

#include<stdio.h>int main(){int num;//弄一个大桶装所有可能出现的数,用来记录每个数字出现的次数,桶的个数是可能出现的最大值 int b[1000]={0};int i,j;for(i=0;i<10;i++){scanf("%d",&num);//该数字出现次数+1 b[num]++;}for(i=0;i<1000;i++){//桶有装有几个数就输出几次 for(j=0;j<b[i];j++)printf("%d ",i);} return 0;}

这方法够简单够粗暴吧
其实这方法还可以优化一下
我们虽然是知道范围,但输入的数的范围可能要比给出的范围少得多,这样的话遍历全部桶就很浪费时间了
所以我们可以找到输入数字的最大值和最小值,只需遍历最大值和最小值之间的桶就行了,因为其他桶都是0,不用输出

所以代码就可以改为

#include<stdio.h>int main(){int num;//弄一个大桶装所有可能出现的数,用来记录每个数字出现的次数,桶的个数是可能出现的最大值 int b[1000]={0};int max=0;int min=1000; int i,j;for(i=0;i<10;i++){scanf("%d",&num);//该数字出现次数+1 b[num]++;/ 到最大值,后面输出可以节省时间,最大值后面的桶都是0,也可以再找最小值,最小值前面的桶都是0 if(num>max){max=num;}if(num<min){min=num;}}//遍历最大值和最小值之间的桶 for(i=min;i<=max;i++){//桶有装有几个数就输出几次 for(j=0;j<b[i];j++)printf("%d ",i);}return 0;}

桶的编码对应的是它记录的数字

然后有人就问如果有负数怎么办

负数的话,把全部桶平移一下就好,输出时把桶的编码再减去平移值
比如范围是-10~9
可以开个数组int b[20];
输入的话就是b[num+10]++
输出的话printf(“%d “,i-10);
这个算法大概就是这样了,虽然说是简单,但是我们通常情况下是不知道确切的范围的,如果以最大范围去开辟桶就会很浪费空间

然后接下来讲第二种算法

插入排序

插入排序的基本思想是,从第二个数开始,插入到前面有序序列的位置
插入排序

比如说3个数,分别是5,4,2
然后从第二个数开始
4比5小,应该插到5的前面
然后5后退一位
现在的序列编程4,5,2

然后到第三个数2
2应该插到4前面
所以4和5都要后退一位
现在就变成2,4,5的有序序列了

具体代码是这样

#include<stdio.h>int main(){int a[1000];int b;int i;for(i=0;i<10;i++){scanf("%d",&a[i]);//还可以在输入的时候就排序了 }for(i=1;i<10;i++){int temp=a[i];int n=i-1;//跟前面的比较,小的话就向前,并且该位向后移动一位 while(n>-1&&temp<a[n]){a[n+1]=a[n];n--;}/ 到位置后放置 a[n+1]=temp;} for(i=0;i<10;i++){printf("%d ",a[i]);} return ;}

第二个for循环i=1就是从第二个数开始

可能需要大家一点抽象思维去想象

比如排队
是按号排队的
他迟到了
然后他就拿这号从最后一位一直向前问
后面的都比他大,终于找到一个比他小的
他不可能排他前面,所以只能排他后面
然后他就插队进去了
他后面的人都被他挤后了一位

接下来介绍另一种排序算法

冒泡排序

冒泡排序的思想是,每次把最小的数冒到左边
就像气泡一样越接近水面的泡泡越大
这里写图片描述

继续是以刚刚的数列5,4,2为例
从第一个数开始
5比4大,然后就交换
4比2大然后就交换
然后现在的序列是2,5,4
然后到第二个数开始
5比4大,交换位置
然后这个序列就排好了

具体代码如下

#include<stdio.h>int main(){int a[1000];int i,j,temp;for(i=0;i<10;i++){scanf("%d",&a[i]);}for(i=0;i<9;i++){//跟后面的所有数进行比较,大的就交换 for(j=i+1;j<10;j++){//交换 if(a[i]>a[j]){temp=a[i];a[i]=a[j];a[j]=temp;}}}for(i=0;i<10;i++){printf("%d ",a[i]);}return 0;} 

这种排序方法是初学者必须掌握的一种排序方法

最后讲一种高级一点的算法

快速排序

掌握这种方法可以说是初学者的分水岭
这种排序方法包含了递归和分治的思想

递归我们最熟悉的就是猴子吃桃
最后一天剩一个,每天吃总数的一半,吃了五天,然后问你最开始有多少个桃子
然后就是从最后一天开始算,一直算到第一天

分治就是,讲一个问题分开处理
但分开处理是没有影响的
就比如扫地
可以扫地分为扫客厅和扫房间

快速排序的思想是从给一个数组,然后在数组中找一个基准值
两边派一个士兵去帮我找数
要从右边的士兵开始
右边的士兵要找一个比基准值小的数
找到后停下来等左边的士兵
左边的士兵要找一个比基准值大的数
找到后就停下来,交换这两个数的位置
交换后继续找,直到他们相遇
相遇时这个数一定比基准值小
大家直到为啥吗
我们有一个很关键的一步
从右边开始
右边停下的位置一定是小于基准值的
相遇后相遇的数和基准值交换,我们这里取最左边的数为基准值
交换之后,基准值的左边都是比基准值小的,基准值右边都是比基准值大的

然后就按相同的规则排基准值的左边和右边
排序时不仅要传入数组,还要传入范围
一旦排到左边界等于右边了就不用排了,就可以return返回了

代码如下

#include<stdio.h>int main(){int a[1000];int i;for(i=0;i<10;i++){scanf("%d",&a[i]);}quicksort(a,0,9);for(i=0;i<10;i++){printf("%d ",a[i]);}return 0;} void quicksort(int a[],int left,int right){if(left>=right){return;} int low=left;int high=right;//这个基准值可以随便取,只要在left和right范围内就好 int key=a[left];while(low!=high){        //顺序很重要,要先从右边开始找//因为最后交换时左边的要都比基准小 //右边大于基准值就跳过 while(low<high&&a[high]>=key){high--;}//左边小于基准值就跳过 while(low<high&&a[low]<=key){low++;}if(low<high){int temp=a[low];a[low]=a[high];a[high]=temp;}}//退出循环时low=high a[left]=a[low];a[low]=key;quicksort(a,left,low-1);//继续处理左边的,这里是一个递归的过程     quicksort(a,low+1,right);//继续处理右边的 ,这里是一个递归的过程 }

如果大家理解了这种算法,对c语言的造诣就会深一层

http://blog.csdn.net/qq_32198277/article/details/50986018
这篇关于快速排序博客有配图更加形象

这里讲的都是从小到大的排序,大家可以思考一下用这几种算法如何从大到小排序

0 0
原创粉丝点击