七种常见的数组排序算法整理(C语言版本)

2019 iOS面试题大全---全方面剖析面试
2018 iOS面试题---算法相关
1、七种常见的数组排序算法整理(C语言版本)
2、2019 算法面试相关(leetcode)--数组和链表
3、2019 算法面试相关(leetcode)--字符串
4、2019 算法面试相关(leetcode)--栈和队列
5、2019 算法面试相关(leetcode)--优先队列
6、2019 算法面试相关(leetcode)--哈希表
7、2019 算法面试相关(leetcode)--树、二叉树、二叉搜索树
8、2019 算法面试相关(leetcode)--递归与分治
9、2019 算法面试相关(leetcode)--贪心算法
10、2019 算法面试相关(leetcode)--动态规划(Dynamic Programming)
11、2019 算法面试相关(leetcode)--动态规划之背包问题


~~~C语言版本~~~

  • 冒泡排序
  • 选择排序
  • 直接插入排序
  • 二分插入排序
  • 希尔排序
  • 快速排序
  • 堆排序
#define EXCHANGE(num1, num2)  { num1 = num1 ^ num2;\
num2 = num1 ^ num2;\
num1 = num1 ^ num2;}

排序算法是否稳定:相同元素的相对在排序前后是否会发生改变,如果会,就是不稳定的,否则就是稳定的。
一.冒泡排序
冒泡排序原理很容易理解,就是重复地走访过要排序的元素列,依次比较两个相邻的元素,顺序不对就交换,直至没有相邻元素需要交换,也就是排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

  • 冒泡排序是一种稳定排序算法。
  • 时间复杂度:最好情况(初始情况就是正序)下是o(n),平均情况是o(n²)
void buddleSort(int num[],int count)
{
    for (int i = 0; i < count - 1; i++) {

        for (int j = 0; j < count - i - 1; j++) {

            if (num[j] > num[j + 1]) EXCHANGE(num[j], num[j + 1])
        }
    }
}

二、选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。
选择排序的交换操作介于 0 和 (n - 1) 次之间。选择排序的比较操作为 n (n - 1) / 2 次之间。选择排序的赋值操作介于 0 和 3 (n - 1) 次之间。
比较次数O(n²),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+...+1=n*(n-1)/2。交换次数O(n),最好情况是,已经有序,交换0次;最坏情况交换n-1次,逆序交换n/2次。交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快

  • 选择排序是不稳定的排序方法。
  • 时间复杂度:最好和平均情况下都是O(n²)
void selectSort(int num[],int count)
{
    for (int i = 0; i < count; i++) {

        int min = i;

        for (int j = i; j < count; j++) {
            
            if (num[j] < num[min])  min = j;
        }

        if (i != min)   EXCHANGE(num[i], num[min]);//可以看出,最多交换count - 1次
    }
}

三、直接插入排序
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,
插入排序的基本思想是:每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止

  • 直接插入排序是稳定的排序算法。
  • 时间复杂度:最好情况(初始情况就是正序)下是o(n),平均情况是o(n²)
void insertSort2(int num[],int count)
{
    int i,j;
    
    for (i = 1; i < count; i++) {
        
        if (num[i] < num[i - 1]) {
            
            int temp = num[i];
            
            for (j = i; j > 0; j--) {
                
                if (num[j - 1] > temp) num[j] = num[j - 1];
                
                else break;
            }
            
            num[j] = temp;
        }
    }
}

四、二分插入排序

由于在插入排序过程中,待插入数据左边的序列总是有序的,针对有序序列,就可以用二分法去插入数据了,也就是二分插入排序法。适用于数据量比较大的情况。
二分插入排序的算法思想:
算法的基本过程:
(1)计算 0 ~ i-1 的中间点,用 i 索引处的元素与中间值进行比较,如果 i 索引处的元素大,说明要插入的这个元素应该在中间值和刚加入i索引之间,反之,就是在刚开始的位置 到中间值的位置,这样很简单的完成了折半;
(2)在相应的半个范围里面找插入的位置时,不断的用(1)步骤缩小范围,不停的折半,范围依次缩小为 1/2 1/4 1/8 .......快速的确定出第 i 个元素要插在什么地方;
(3)确定位置之后,将整个序列后移,并将元素插入到相应位置。

  • 二分插入排序是稳定的排序算法。
  • 时间复杂度:最好情况(刚好插入位置为二分位置)下是O(log₂n),平均情况和最坏情况是o(n²)
void insertSortBinary(int num[],int count)
{
    int i,j;
    
    for (i = 1; i < count; i++) {
        
        if (num[i] < num[i - 1]) {
            
            int temp = num[i];
            
            int left = 0,right = i - 1;
            
            while (left <= right) {
                
                int mid = (left + right)/2;
                
                if (num[mid] < temp) left = mid + 1;
                    
                else right = mid - 1;
            }
            //只是比较次数变少了,交换次数还是一样的
            for (j = i; j > left; j--) {
                
                num[j] = num[j - 1];
            }
            
            num[left] = temp;
        }
    }
}

五、希尔(插入)排序
希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,排序完成。

  • 希尔排序是非稳定排序算法。
  • 时间复杂度:O(n^(1.3—2))
void shellSort(int num[],int count)
{
    int shellNum = 2;
    int gap = round(count/shellNum);

    while (gap > 0) {
        for (int i = gap; i < count; i++) {
            int temp = num[i];
            int j = i;
            while (j >= gap && num[j - gap] > temp) {
                num[j] = num[j - gap];
                j = j - gap;
            }
            num[j] = temp;
        }
        gap = round(gap/shellNum);
    }
}

六、快速排序
快速排序(Quicksort)是对冒泡排序的一种改进。

它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

  • 快速排序是非稳定的排序算法
  • 时间复杂度:最差为O(n^2),平均为O(nlogn),最好为O(nlogn)
void quickSort(int num[],int count,int left,int right)
{
    if (left >= right){
        
        return ;
    }
    int key = num[left];
    int lp = left;           //左指针
    int rp = right;          //右指针
    while (lp < rp) {
        if (num[rp] < key) {
            int temp = num[rp];
            for (int i = rp - 1; i >= lp; i--) {
                num[i + 1] = num[i];
            }
            num[lp] = temp;
            lp ++;
            rp ++;
        }
        rp --;
    }
    quickSort(num,count,left,lp - 1);
    quickSort(num,count,rp + 1,right);
}

七、堆排序
是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点

在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:

  • 最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点

  • 创建最大堆(Build Max Heap):将堆中的所有数据重新排序

  • 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算

  • 堆排序是一个非稳定的排序算法。
  • 时间复杂度:O(nlogn)
void maxHeapify(int num[], int start, int end) {
    //建立父节点指标和子节点指标
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子节点指标在范围内才做比较
        if (son + 1 <= end && num[son] < num[son + 1]) //先比较两个子节点大小,选择最大的
            son++;
        if (num[dad] > num[son]) //如果父节点大於子节点代表调整完毕,直接跳出函数
            return;
        else { //否则交换父子内容再继续子节点和孙节点比较
            EXCHANGE(num[dad], num[son])
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

void heapSort(int num[], int count) {
    int i;
    //初始化,i从最後一个父节点开始调整
    for (i = count / 2 - 1; i >= 0; i--)
        maxHeapify(num, i, count - 1);
    //先将第一个元素和已排好元素前一位做交换,再重新调整,直到排序完毕
    for (i = count - 1; i > 0; i--) {
        EXCHANGE(num[0], num[i])
        maxHeapify(num, 0, i - 1);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,170评论 0 52
  • 面试中常用的几个基本算法整理记录(二) 无意中看到了面试中的 10 大排序算法总结原文地址记录一下,方便查找。 查...
    190CM阅读 1,754评论 1 13
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    闲云清烟阅读 757评论 0 6
  • 不动声色的刺人才最伤人。 我刚才面试被狠狠的刺了一通。我本来抱有希望的,结果面对的HR不动声色的给了几刀。如果说之...
    明初的日记本阅读 236评论 0 0
  • 名人分别为:亚里士多德,牧师葛培理,马丁路德,爱因斯坦,诗人毛姆,加拿大银行家Acetone, 美国音乐家Wond...
    舒己怀_Frank阅读 565评论 10 21