剑指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=pivot)
                right--;
            if(left
归并排序:
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]
堆排序:
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;i1;){
            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;idata[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
插入排序:
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;i0 && 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=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   

你可能感兴趣的:(剑指offer第二版-排序算法)