剑指offer第二版-排序算法

本系列导航:剑指offer(第二版)java实现导航帖

查找和排序是经常用到的基本算法。查找相对而言较简单,不外乎顺序查找,二分查找,哈希表查找,二叉排序树查找。而排序相对而言复杂些,因为排序算法较多,而且要明确各排序算法的时间复杂度,空间复杂度,稳定性。而这些点都是面试中重要内容。
原书并未详细实现全部排序,本文的目标就是做个系统的排序算法总结。

1. 说明:

% 说明
1 只包含数组的排序。单链表的排序将单独总结。
2 只包含基于比较的基本排序算法。计数排序,桶排序同样重要,但使用条件特殊,本文不进行合并总结。
3 并未涉及多线程排序与海量数据的排序问题。
4 由于书写问题或认识有限,难免出现错误。若发现欢迎指正。

2. 排序算法比较:

排序算法 时间复杂度 空间复杂度 稳定性 简要介绍
快排quickSort o(nlogn) o(logn) 不稳定举例:1,2,3(A),3(B)=》1,2,3(B),3(A) (小数,基准值,大数)
归并排序mergeSort o(nlogn) o(n) 稳定 把数据分为两个有序段,从两段中逐个选最小的元素移入新数据段的末尾。
堆排序heapSort o(nlogn) o(1) 不稳定举例:2(A),2(B),2(C)=》2(C),2(B),2(A) 建立最大堆,交换堆的第一个与最后一个元素,调整堆(堆排序的0号元素不能使用)。
冒泡排序bubbleSort o(n^2) o(1) 稳定 (无序区,有序区)无序区从左到右通过两两交换找出最大元素放到有序区的左边。
选择排序selectionSort o(n^2) o(1) 不稳定举例:2(A),2(B),1=》1,2(B),2(A) (有序区,无序区)。从右到左在无序区里找一个最小的元素跟在有序区的后面。比较得多,换得少。
插入排序insertionSort o(n^2) o(1) 稳定 (有序区,无序区)。从左到右把无序区的第一个元素插入到有序区的合适的位置。比较得少,换得多。
希尔排序shellSort o(n^1.3) o(1) 不稳定举例:2(A),1(A),1(B),2(B)=》1(B),1(A),2(A),2(B) 每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1。

希尔排序并无一个确定、可计算的时间复杂度。次数值在1~2之间。有人在大量的实验后得出结论:当n在某个特定的范围后希尔排序的比较和移动次数减少至n^1.3。

3.java实现

快排:
package chapter2;

/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
    //数组快排,时间o(nlogn)(最差n^2),空间o(logn)(最差n),递归造成的栈空间的使用,不稳定
    public static void quickSort(int[] data){
        if(data==null || data.length<=1) return;
        quickSortCore(data,0,data.length-1);
    }
    public static void quickSortCore(int[] data,int start,int end){
        if(end-start<=0)
            return;
        int index = quickSortPartition(data,start,end);
        quickSortCore(data,start,index-1);
        quickSortCore(data,index+1,end);
    }
    public static int quickSortPartition(int[] data,int start,int end){
        //选择第一个值作为基准
        int pivot = data[start];
        int left = start,right = end;
        while(left<right){
            while(left<right && data[right]>=pivot)
                right--;
            if(left<right)
                data[left] = data[right];
            while(left<right && data[left]<pivot)
                left++;
            if(left<right)
                data[right] = data[left];
        }
        data[left] = pivot;
        return left;
    }
    public static void testQuickSort(){
        int[] data = {5,4,3,1,2};
        quickSort(data);
        System.out.print("数组快速排序:\t");
        for(int item: data){
            System.out.print(item);
            System.out.print('\t');
        }
        System.out.println();
    }
}
归并排序:
package chapter2;

/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
    //数组二路归并,时间o(nlogn),空间o(n),稳定
    public static int[] mergeSort(int[] data){
        if(data==null || data.length<=1)
            return data;
        mergeSortCore(data,0,data.length-1);
        return data;
    }
    //对data[start~mid],data[mid+1~end]归并
    //典型的分治结构:结束条件+分治+和
    public static void mergeSortCore(int[] data,int start,int end){
        if(start>=end)
            return;
        int mid = start + (end - start)/2;
        mergeSortCore(data,start,mid);
        mergeSortCore(data,mid+1,end);
        mergeSortMerge(data,start,mid,end);
    }
    public static void mergeSortMerge(int[] data,int start,int mid,int end){
        if(end==start)
            return;
        int[] temp = new int[end-start+1];
        int left = start,right = mid+1,tempIndex = 0;
        while(left<=mid && right<=end){
            if(data[left]<data[right])
                temp[tempIndex++] = data[left++];
            else
                temp[tempIndex++] = data[right++];
        }
        while(left<=mid)
            temp[tempIndex++] = data[left++];
        while(right<=end)
            temp[tempIndex++] = data[right++];
        for(int i=0;i<temp.length;i++)
            data[start+i] = temp[i];
    }
    public static void testMergeSort(){
        int[] data = {5,4,3,1,2};
        mergeSort(data);
        System.out.print("数组归并排序:\t");
        for(int item: data){
            System.out.print(item);
            System.out.print('\t');
        }
        System.out.println();
    }
}
堆排序:
package chapter2;

/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
    //数组堆排序,时间o(nlogn),空间o(1),不稳定
    //建立最大堆,交换堆的第一个与最后一个元素,调整堆
    //注意,堆排序的0号元素不能使用,为了与其他排序统一接口,先把最小的元素放到0号元素上,再用堆排序
    public static void heapSort(int[] data){
        if(data==null || data.length<=1)
            return;
        //先把最小的元素放到0号元素上
        int minIndex = 0;
        for(int i=1;i<data.length;i++){
            if(data[i]<data[minIndex])
                minIndex = i;
        }
        if(minIndex!=0){
            int temp = data[0];
            data[0] = data[minIndex];
            data[minIndex] = temp;
        }
        //正式开始堆排序(如果0号元素未存值,省略上述代码)
        buildMaxHeap(data);
        for(int indexBound = data.length-1;indexBound>1;){
            int temp = data[indexBound];
            data[indexBound] = data[1];
            data[1] = temp;
            indexBound--;
            adjustMaxHeap(data,1,indexBound);
        }
    }
    public static void buildMaxHeap(int[] data){
        for(int i = data.length/2;i>0;i--){
            adjustMaxHeap(data,i,data.length-1);
        }
    }
    //i表示待调整元素下标,end表示最大堆的最后一个元素的下标,end值会随着排序的进行而减小到1
    public static void adjustMaxHeap(int[] data,int i,int end){
        int left = 2*i;
        int right = 2*i+1;
        int max = i;
        if(left<=end && data[left]>data[max])
            max = left;
        if(right<=end && data[right]>data[max])
            max = right;
        if(max!=i){
            int temp = data[max];
            data[max] = data[i];
            data[i] = temp;
            adjustMaxHeap(data,max,end);
        }
    }

    public static void testHeapSort(){
        int[] data = {5,4,3,1,2};
        heapSort(data);
        System.out.print("数组堆排序:\t");
        for(int item: data){
            System.out.print(item);
            System.out.print('\t');
        }
        System.out.println();
    }
}
冒泡排序:
package chapter2;

/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
    //数组冒泡,时间o(n^2),空间o(1),稳定
    public static void bubbleSort(int[] data){
        if(data==null || data.length<=1)
            return;
        for(int i=0;i<data.length-1;i++){
            for(int j=1;j<data.length-i;j++){
                if(data[j-1]>data[j]){
                    int temp = data[j-1];
                    data[j-1] = data[j];
                    data[j] = temp;
                }
            }
        }
    }
    public static void testBubbleSort(){
        int[] data = {5,4,3,1,2};
        bubbleSort(data);
        System.out.print("数组冒泡排序:\t");
        for(int item: data){
            System.out.print(item);
            System.out.print('\t');
        }
        System.out.println();
    }
}
选择排序:
package chapter2;

/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
    //数组选择排序,时间o(n^2),空间o(1),不稳定
    public static void selectionSort(int[] data){
        if(data==null || data.length<=1)
            return;
        for(int i=0;i<data.length-1;i++){
            int minIndex = i;
            for(int j=i+1;j<data.length;j++){
                if(data[j]<data[minIndex])
                    minIndex = j;
            }
            if(i!=minIndex) {
                int temp = data[i];
                data[i] = data[minIndex];
                data[minIndex] = temp;
            }
        }
    }
    public static void testSelectionSort(){
        int[] data = {5,4,3,1,2};
        selectionSort(data);
        System.out.print("数组选择排序:\t");
        for(int item: data){
            System.out.print(item);
            System.out.print('\t');
        }
        System.out.println();
    }
}
插入排序:
package chapter2;

/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
    //数组插入排序,时间o(n^2),空间o(1),稳定
    public static void insertionSort(int[] data){
        if(data==null || data.length<=1)
            return;
        for(int i=1;i<data.length;i++){
            int j=i;
            int temp = data[i];
            while(j>0 && data[j-1]>temp) {
                data[j] = data[j-1];
                j--;
            }
            data[j] = temp;
        }
    }
    public static void testInsertionSort(){
        int[] data = {5,4,3,1,2};
        insertionSort(data);
        System.out.print("数组插入排序:\t");
        for(int item: data){
            System.out.print(item);
            System.out.print('\t');
        }
        System.out.println();
    }
}
希尔排序:
package chapter2;

/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
    //数组希尔排序(插入排序缩小增量),时间o(n^1.3),空间o(1),不稳定
    //时间复杂度是模糊的,有人在大量的实验后得出结论:当n在某个特定的范围后希尔排序的比较和移动次数减少至n^1.3。次数取值在1到2之间。
    public static void shellSort(int[] data){
        if(data==null || data.length<=1)
            return;
        for(int d=data.length/2; d>0; d=d/2){
            for(int i=d;i<data.length;i++){
                int cur = i;
                int temp = data[i];
                while(cur>=d && data[cur-d]>temp){
                    data[cur] = data[cur-d];
                    cur = cur - d;
                }
                data[cur] = temp;
            }
        }
    }
    public static void testShellSort(){
        int[] data = {5,4,3,1,2};
        shellSort(data);
        System.out.print("数组希尔排序:\t");
        for(int item: data){
            System.out.print(item);
            System.out.print('\t');
        }
        System.out.println();
    }
}

4. 测试

package chapter2;
/**
 * Created by ryder on 2017/6/25.
 * 数组排序算法
 */
public class P79_Sort {
   public static void main(String[] args){
        testQuickSort();
        testMergeSort();
        testHeapSort();
        testBubbleSort();
        testSelectionSort();
        testInsertionSort();
        testShellSort();
    }

结果:

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

推荐阅读更多精彩内容

  • 本系列导航:剑指offer(第二版)java实现导航帖 考查排序算法时大多数情况下被排序数据都是数组形式,但也有可...
    ryderchan阅读 1,928评论 0 2
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,101评论 0 52
  • 该系列文章主要是记录下自己暑假这段时间的学习笔记,暑期也在实习,抽空学了很多,每个方面的知识我都会另起一篇博客去记...
    Yanci516阅读 12,060评论 6 19
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,172评论 0 2
  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,704评论 0 15