算法学习1_排序

题目一 桶排序
高考结束了,班主任需要计算班里学生的总分和并且从大到小排序?

解答:
最高分 是 750分 所以我们建立的桶需要 大于 750 个 我们这里使用 1000 个
桶排序的核心思想
根据该数组中值的范围,定一个包括所有值的数组,比如一个班的学生的高考总数进行排序那么就确定一个数组int book[1001]
这样
就用book数组的角标值标识分数,从0到1000。然后遍历需要排序的数组,把每个角标所存储的值,作为book数组的角标,然后对book数组
当前角标的值进行++,从而确定了每个分数有多少人得了这个分数,然后再遍历book数组,根据socre所存储的值的大小去确认当前分数出现
的次数,这样就完成了对分数数组进行排序。
这里我们定义的包括所有值的数组socre,其实就是拿了一排桶过来,桶上面有编号0-1000,然后把我们需要排序的小球数组,根据小球的编号(分数),分别放入这个桶里面,然后去数每一个桶里出现了多少个小球,从而完成了排序

int main(int argc, const char * argv[]) {
    int book[1001];
    int i,j,t,n;
    
    for (i = 0; i < 1001; i ++) {
        book[i] = 0;
    }
    printf("输入一个数n,表示之后将要输入n个数:");
    scanf("%d",&n);
    for (i = 0; i < n + 1 ; i ++) {
        // 循环读入n个数,并进行桶排序
        printf("请输入分数:");
        scanf("%d",&t);
        book[t]++;
    }
    
    for (i = 1000; i >= 0; i --) {
        for (j = 1; j <= book[i]; j ++) {
            printf("%d  ",i);
        }
    }
}

空间复杂度:
所谓的算法的空间复杂度,其实简单的理解就是该算法运行时,临时占用存储空间大小的度量。说白了,其实就是这个算法
运行的时候,会消耗多大的内存,那么桶排序的空间复杂度是什么样的呢??从我们写的算法可以看出,其实该算法主要占用内存空
间的是原始数据数组和桶数组,所以随着数据量的增加和数据内容的复杂,所需要的内存
越多。
时间复杂度:
所谓的算法的时间复杂度,其实就是算法运行所需的时间,我们近似的将每一行代码的执行时间看为相同,那么桶排序的
所需要的时间,就是第4行执行次数m,和第7行执行次数n,简单的标示就是O(m+n)。桶排序其实是一种相当快速的排序方式。

桶排序缺点:桶排序的的空间复杂度较高 ,如果计算大量的数据,需要消耗的内存空间是相当大的

题目二 冒泡排序
高考结束了,班主任需要计算班里学生的总分和并且从大到小排序,并且排序要把相应的名字对应起来

冒泡排序核心思想 :冒泡排序的基本思想是:每次比较两个相邻的元素,如果它们的顺序错误就把它们交换 过来。
这里可以使用冒泡排序

// 用于冒泡排序 这里创建了一个结构体用来存储姓名和分数
struct student
{
    char name[21];
    char score;
};
    //下面这些方法在main方法里面 
int main(int argc, const char * argv[]) {
    // 冒泡排序,结构体可以得到分数和分数对应的人 

    struct student a[100], t; // a[100] 和 t 都是结构体对象 学生小于100人
    int i,j,n;
    
    printf("输入一个数n,代表之后要排序的个数为n个:");
    scanf("%d",&n);
    
    for (i = 0; i < n; i ++) {
        printf("请输入一个数");
        scanf("%s %d",a[i].name , &a[i].score);
        
    }
    // 冒泡算法核心比较邻居的大小,来交换位置
    for (i = 0; i < n; i ++) {
        for (j = 0; j < n - i; j ++) {
            if (a[j].score < a[j+1].score) {
                t = a[j];
                a[j] = a[j+1];
                a[j+1] = t;
            }
        }
    }
    
    for (i = 0; i < n; i++) {
        printf("%s, %d ",a[i].name,a[i].score);
    }
}
    

时间复杂度: 冒泡排序的核心部分是双重嵌套循环,时间复杂度是O(N^ 2) 这个时间复杂度是相当高的,所以一般这个算法除了我们听的比较多,一般都不太推荐使用

题目三 最常用的排序-快速排序
高考结束了,某县要求需要计算该县里学生的总分和并且从大到小排序?
分析: 假设计算机每秒计算1亿次一个该县 高三有100000个人,我们需要对着100000个人的分数进行排序 使用 冒泡排序 需要100亿次 ,需要100秒,有没有更快的呢,当然有,快速排序

快速排序:这个有点复杂,我来举个简单例子
假如 要对 6 1 2 7 9 3 4 5 10 8,进行排序,快速排序,首先要在队列里面随便找一个数作为"基准数",为了方便,就让第一个数 6 作为基准数吧。接下来,需要将这个序列中 所有比基准数大的数放在 6 的右边,比基准数小的数放在 6 的左边,类似下面这种排列。
实际上会经过下面的流程

排序1
第一步 首先以6位基准数 ,从右到左(注意:一定是先右后左) 开始找基准数小的数为5 ,从左往右比6大的数是7 ,然后 5 和 7交换位置变为
6 1 2 5 9 3 4 7 10 8

第二步 首先以6位基准数 ,从右到左 开始找基准数小的数为4 ,从左往右比6大的数是4 ,然后 4 和 9交换位置变为
6 1 2 5 4 3 9 7 10 8

第三步 首先以6位基准数 ,从右到左 开始找基准数小的数为3 ,从左往右比6大的数在找到之前和3相遇,然后 6 和 3交换位置变为
3 1 2 5 4 6 9 7 10 8
进过上面排序之后,大于基准数6的有 9,7,10,0,8 , 小于基准数的有 3,1,2,5,4

排序2
3,1,2,5,4 我们让3作为基准数, 再次重复上面操作
得到 2,1,3,5,4 基准数 左边有 2,1 右边有5,4

9,7,10,0,8 我们让9作为基准数, 再次重复上面操作
得到0,7,8,9,10 基准数左边有0,7,8,右边有10

排序n次
重复上面操作,最后可以得到
1 2 3 4 5 6 7 8 9 10

下面是demo实现

int a[100001];//定义全局变量,用于学生存储分数 需要大于人数100000
void quickSort (int left, int right); // left 代表左边分数下标编号 right右边分数下标编号 


int main(int argc, const char * argv[]) {
    int i,n ;
    printf("输入一个数字n,代表之后会有n个人:");
    scanf("%d",&n);
    for (i = 0; i < n; i++) {
        printf("输入一个成绩:");
        scanf("%d",&a[i]); 
    }
    
    quickSort(0, n - 1);
    
    for (i = 0; i < n; i ++) {   // 冒泡排序,和快速排序都是使用该方法去重
         printf("%d ",a[i]); // 我们这里不需要去重
       // if (a[i] != a[i + 1]) { // 去重
           // printf("%d ",a[i]);
        //}
    }
     getchar();
}
/**
 快速排序

 @param left 左边的哨兵下标
 @param right 右边的哨兵下标
 */
void quickSort (int left, int right)
{
    int i ,j ,t ,temp;
    if (left > right) {
        return;
    }
    
    temp = a[left]; // temp 中存的就是基准数
    
    i = left;
    j = right;
    
    while (i != j) {  // 左右两个哨兵没有相遇的时候
        
        // 顺序很重要,首先right哨兵从右往左开始移动
        while (a[j] >= temp && i < j) {
            j --;
        }
        //  然后left哨兵从左往右开始移动
        while (a[i] <= temp && i < j) {
            i ++;
        }
        
        // 两个哨兵都结束的时候,交换位置
        if (i < j) { // 两个哨兵没有相遇得时候
            t = a[i];
            a[i] = a[j];
            a[j] = t;
         }
    }
    //最终将基准数归位
    
    a[left] = a[i]; // 重新定义新的left哨兵
    a[i] = temp;
    
    quickSort(left, i - 1);  // 继续处理左边的,这是一个递归的过程
    quickSort(i + 1, right); // 继续处理右边的,只是一个递归的过程
    
}

输入成绩别较真,还是用上面的测试数据6 1 2 7 9 3 4 5 10 8进行排序,这只是一个演示

优点: 快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候 设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全 部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进 行交换,交换的距离就大得多了。因此总的比较和交换次数就少了,速度自然就提高了。当 然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和 冒泡排序是一样的,都是 O(N2),它的平均时间复杂度为 O (NlogN)。其实快速排序是基于一 种叫做“二分”的思想

还有大家别以为这个时间复杂度没变多少,我举个例子
假如我 们的计算机每秒钟可以运行 10 亿次,那么对 1亿个数进行排序
桶排序需要 0.1秒,
冒泡排序则需要 1千万秒,达到 115 天之久,是不是很吓人?
快速排序则需要8 秒


本次学习就到这里了,我们学习了常见的三种排序方式,桶排序、冒泡排序、快速排序,对他们的思想和实现原理也进行了深入分析。最好自己动手,不看相关代码,去实现一遍,看看自己是否已经掌握了这几种排序方式。
算法这个东西,听起来很吓人,但是只要认真学习,还是很有意思的。
本人也是刚刚学习,如有错误,请多多指正。
本文部分内容参考 【啊哈!算法】这本书
代码例子

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,706评论 0 15
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,101评论 0 52
  • 前言 查找和排序算法是算法的入门知识,其经典思想可以用于很多算法当中。因为其实现代码较短,应用较常见。所以在面试中...
    宝塔山上的猫阅读 1,043评论 1 21
  • 小城的土话十里不同音,仅是“这样”一词,就有“niang 老”、“ang 老”、“jia 老”等等说法。称谓也一样...
    陸鋒阅读 441评论 0 1
  • 文章写于四年前,那时候,我还是一个任性的小女孩,不懂得爱,却依旧爱,总以为,只要不分开,那就是永恒。 该从什么时候...
    心有余响阅读 236评论 0 1