几种常用排序算法简单实现和分析

  • 写在之前


  • 代码实现 Java
  • 设计模式 策略模式
// 接口定义
public interface Sorter {
    public void sort(int []data);
}
// 测试入口函数
public static void main(String[] args) {
        int []data = new int[] {2,5,6,3,4,6,1,8,9,12,56,4,3,7,9,6,8};
        Sorter sorter = new //具体实现类
        sorter.sort(data);
        for(int i:data) {
            System.out.println(i);
        }
    }

  • 冒泡排序

似乎是这个世界上最简单的排序算法,很多Coder最初学会的排序算法, 简单思路清晰,通过一次次的循环找出最值元素将其浮到“边界”,因其过程十分相似冒泡,就得到了这个十分形象的名字。

public class BubbleSort implements Sorter{

    @Override
    public void sort(int[] data) {
        for(int i=0; i<data.length;i++) {
            for(int j=0; j<i;j++) {
                if(data[i] > data[j]) {
                   //交换 data[i]和data[j]的值  当时突然想起了怎么在不引入中间变量交换值 0.0
                    data[i] = data[i]^data[j];
                    data[j] = data[i]^data[j];
                    data[i] = data[i]^data[j];
                }
            }
        }
    }
}
  • 时间复杂度 O(n^2)
  • 空间复杂度 O(1) (雾 如果这样写明明是0
  • 稳定的排序

  • 直接插入排序

一种简单暴力排序算法,将待排序的数字依次插入一个有序数组中,平时很少用到,反而在一些往已经有序的数组插入数据的场合使用。

public class InsertionSort implements Sorter{

    @Override
    public void sort(int[] data) {
        for(int i=0; i<data.length; i++) {          
            for(int j = i-1;j>=0;j--) {
                if(data[j] > data[j+1]) {
                    int temp = data[j+1];
                    data[j+1] = data[j];
                    data[j] = temp;
                }else {
                    break;
                }
            }   
        }
    }
}
  • 时间复杂度 O(n^2)
  • 空间复杂的有 O(1)
  • 稳定 的排序
    相比于冒泡排序没什么优点 还多了一句 怪不得很少人使用。

  • 归并排序

一种思想简单,且具有魔力的排序,使用分治的思想 先拆分数据为2部分 分别保证左边和右边同样有序 再将其有序地归并起来,其实简而言之,我觉得归并排序本身就是在不停地拆和并。使用的情景非常丰富,是一种高效的排序手段。

  • 简单举例

8,13,9,12,56,4,3,7,12;

拆成子元素
8        9       56       3      12
    13       12       4      7
第一趟归并
8 13         4 56        12
      9 12         3 7
第二趟
8 9 12 13    12
        3 4 7 56 
//中间略归并一步
3 4 7 8 9 12 12 13 56
public class MergcSort implements Sorter{

    @Override
    public void sort(int[] data) {
        int[] temp = new int[data.length]
        mergcSort(0, data.length-1, data,temp);     
    }
    
    private void mergcSort(int left,int right,int[]data,int []temp) {
        if(left == right) {
         //当拆分到只有一个元素的时候当然有序咯
            return;
        }
        // 拆拆拆
        int mid = (left+right)/2;
        // 递归拆左边
        mergcSort(left, mid, data);
        // 递归拆右边
        mergcSort(mid+1, right, data);
        
        int x = left,y = mid +1,loc =left;
        while(x<=mid || y<=right) {
            if(x <= mid &&(y>right||data[x] < data[y])) {
             //分2种情形
            //1. x <= mid && y <= right 这时候data[x] 的值小于data[y] 按照原则 谁小谁上
            //2. x <= mid && y > right 即右边的已经全部填充到数组里了 这时候只好填左边的了
                temp[loc] = data[x];
                x++;
            }else {
                temp[loc] = data[y];
                y++;
            }
            loc++;
        }
        // 毫无技巧地将中间数组的值填充回来
        for(int i=left;i<=right;i++) {
            data[i] = temp[i];
        }
        
    }
  • 时间复杂度O(n*log(n))
  • 空间复杂度 O(n)
  • 稳定的排序

  • 快速排序

强大的排序,是最常用的排序算法之一(目测要是是稳定排序的话使用会更丰富),快速排序其实非常简单 简单来说就是不断挖坑和填坑的过程,特点排序效率高,空间复杂度低,非常难得。

  • 简单举例

8,13,9,12,56,4,3,7,12;

选取哨兵 简单取第一位挖掉 【】表示新填充   ()代表挖掉了 哨兵 = 8;
(8) 13 9 12 56 4 3 7 12 ;            挖掉哨兵
#1【7】 13 9 12 56 4 3 (7) 12         从右搜索第一个小于8的 挖掉并填充到上次挖的地方 7
#2 7 (13) 9 12 56 4 3 【13】 12       从左搜索第一个大于8的 挖掉填充到上次挖的地方 13
7 【3】9 12 56 4 (3)13 12             重复#1
7 3 (9)12 56 4 【9】 13 12            #2
7 3 【4】 12  56 (4) 9 13 12          。。。
7  3  4  (12) 56 【12】 9 13 12 
 最后左右重逢了 填充哨兵到相逢的地方
7 3 4 8 56 12 9 13 12 
递归处理左右
[ 7 3 4 ] 8 [56 12 9 13 12]
......
  • 代码实现
public class QuickSort implements Sorter{

    @Override
    public void sort(int[] data) {      
        quickSort(0, data.length-1, data);
    }
    
    private void quickSort(int left,int right,int []data) {
        if(right <= left) {
            return;
        }
        int x = left,y = right;
        int temp = data[x];
        while(x < y) {
            while(y > x && data[y] > temp) {
                y--;
            }
            if(y > x) {
                data[x++]=data[y];
            }
            while(x < y && data[x] < data[y]) {
                x++;
            }
            if(x < y) {
                data[y--] = data[x];
            }
        }
        data[x] = temp;
        quickSort(left, x-1, data);
        quickSort(x+1, right, data);
    }
}

听起来好像很复杂 实际实现起来非常简单 其中2个if是为了保证左右指针不重逢 毕竟重逢意味着填充哨兵,本次排序的结束和分治的开始

  • 时间复杂度O(n*log(n))
  • 空间复杂度 O(1)
  • 不稳定的排序

  • 堆排序

STL中优先队列的底层实现,虽然在一次排序上表现不够优秀,但是非常适合那种不停地插入和取出最值的情景,堆排序事实上是最大堆或者最小堆,属于树形结构这里我就简单写一个堆,接下来不适合0基础的人查看。

public class Heap {

    private int[] data;
    private int size;

    public Heap(int size) {
        data = new int[size];
        size = 0;
    }
       //得到堆顶元素
    public int getTop() {
        return data[0];
    }
 // 入堆
 // 将入堆元素放到堆末尾 再从低而上做一次维护

    public void push(int input) {
        int current = size;
        data[current] = input;
// 计算 父节点的位置
        int father = (current - 1) / 2;
// 维护 这里保证堆中所有的儿子都比父亲大 否则就交换位置 继续向上维护
        while (data[current] < data[father]) {
            data[current] = data[current] ^ data[father];
            data[father] = data[current] ^ data[father];
            data[current] = data[current] ^ data[father];

            current = father;
            father = (father - 1) / 2;
        }
        size++;
    }
// 最值元素出堆 首先将要出堆的元素交换到末尾 再顶定而下做一次维护
    public int pop() {
        int temp = data[0];
        data[0] = data[size-1];
        data[size-1] = temp;    
        size--;     
        update(0,size);
        return data[size];
    }
//自定而下维护函数 如果发现子节点大于父节点的值交换位置 再从新节点位置继续维护  专业的叫法叫 沉底
    private void update(int pos,int size) {
        int lchild = pos*2+1;
        int rchild = pos*2+2;
        
        int min_pos = pos;
        if(lchild < size && data[lchild] < data[min_pos]) {
                min_pos = lchild;
            }
        if(rchild < size && data[rchild] <data[min_pos]) {
                min_pos = rchild;
            }
        if(pos != min_pos) {
           int temp = data[pos];
           data[pos] = data[min_pos];
           data[min_pos] = temp;
           update(min_pos, size);
        }   
    }
}
  • 时间复杂度O(n*log(n))
  • 空间复杂度 O(1)
  • 不稳定的排序
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容

  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,723评论 0 15
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,149评论 0 52
  • 该系列文章主要是记录下自己暑假这段时间的学习笔记,暑期也在实习,抽空学了很多,每个方面的知识我都会另起一篇博客去记...
    Yanci516阅读 12,156评论 6 19
  • 19 98年,米雪13岁,读初二。 如平时一样,米雪要凌晨五点起床,要到5公里外的学校读书,如果晚了,...
    米夜雪阅读 365评论 0 0
  • 孩子又不是图画练习册,你不能光顾着要涂上自己喜欢的色彩。 ——《追风筝...
    我是一小白白阅读 622评论 0 0