排序

2017-04-02  本文已影响16人  大海孤了岛
算法稳定性:

假定在待排序的记录序列中,存在多个具有相同关键字的记录,若经过排序,这些记录的相对次序保持不变。即在原序列中,ri=rj,且ri在rj之前,而在排序后,ri仍在rj之前,则称这种排序算法是稳定的。

排序分类:

排序分类
排序算法
插入排序

插入排序由N-1趟排序组成。对于i=1到N-1趟,插入排序保证从位置0到位置i上的元素已经处于排过序的状态。

如下图:

插入排序.png

具体实现:

public class InsertSort {

    public static void main(String[] args){
        int[] arr = {34,8,64,51,32,21};
        System.out.println("Before sort:");
        printArray(arr);
        System.out.println("After insert sort:");
        insertionSort(arr);
        printArray(arr);
    }

    public static  void printArray(int[] a){
        for (int i = 0; i < a.length; i ++){
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }

    /**
     * 实现思路:从第二个位置开始遍历,保证目标数左边是排序好的,目标数不断
     * 往右边找,直到找到合适的位置放入。
     * @param a
     */
    public static  void insertionSort(int[] a){
        int j;
        //从第二个位置开始
        for (int i = 1; i < a.length; i ++){
            //设置临时变量
            int tmp = a[i];
            //将该位置不断往左移,直到当前的数不大于该数
            for (j = i; j > 0 && tmp < a[j-1] ; j--){
                //将数往右移,为目标数腾一个位置
                a[j] = a[j - 1];
            }
            //找到位置,将目标数放入
            a[j] = tmp;
        }
    }
}

输出结果:
Before sort:
34 8 64 51 32 21 
After insert sort:
8 21 32 34 51 64 

评价:
插入排序的复杂度为O(N2),但算法是稳定的。

希尔排序:

先将序列按Gap划分为元素个数相同的若干数组,使用直接插入排序法进行排序,然后不断缩小Gap直至1,最后使用插入排序完成排序。希尔排序实际上是插入排序的增强版。

如下图:


希尔排序.png

实现过程:

    public static  void shellSort(int[] a){
        int j;
        //设置gap,定义gap/2变化
        for (int gap = a.length / 2; gap > 0; gap /= 2){
            System.out.println("第"  + gap + "趟排序:");
            //每gap间进行插入排序
            for (int i = gap; i < a.length; i ++){
                int tmp = a[i];
                for (j = i; j >= gap && tmp < a[j-gap]; j -= gap){
                    a[j] = a[j-gap];
                }
                a[j] = tmp;
            }
            printArray(a);
        }
    }

输出结果:以第一个位置进行比较


希尔排序.png

评价:

冒泡排序

它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作就是重复地进行直到没有再需要交换,也就是说数列已经排序完成。

如下图:

冒泡排序.png

具体实现:

public static  void bubbleSort(int[] a){
    int temp;
    //遍历N-1趟
    for (int i = 0; i < a.length - 1; i ++){
                //每一躺保证该趟的最后一个元素为最大
        for (int j = 0; j < a.length - i - 1; j ++){
            if (a[j] > a[j+1]){
                temp = a[j];
                a[j] = a[j+1];
                a[j+1] = temp;
            }
        }
    }
}

评价:

快速排序

使用分治法策略来把一个序列分为两个子序列。

快速排序.png

具体实现:

public class QuickSort {
    private int[] arr;

    public QuickSort(int[] arr){
        this.arr = arr;
    }
    //打印数组
    public  void printArray(){
        for (int i = 0; i < arr.length; i ++){
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    public  void quick_sort(){
        quick_sort_recursive(0, arr.length - 1);
    }

    private void quick_sort_recursive(int start, int end){
        //只有一个元素的情况,直接返回
        if (start >= end) return;
        //取最后一个元素作为基准
        int mid = arr[end];
        //设置左右边
        int left = start;
        int right = end - 1;
        //进行比较交换
        while (left < right){
            //左边的数往右找,直到找到大于基准的数
            while (arr[left] <= mid && left < right)
                left ++;
            //右边的数往左找,直到找到小于基准的数
            while (arr[right] >= mid && left < right)
                right --;
            //交换两个数
            Swap(left,right);
        }
        //若中间元素大于基准,则进行交换
        if (arr[left] > arr[end])
            Swap(left,end);
        //否则left++,目的是排除掉中间元素
        else
            left ++;
        //递归左右两边
        quick_sort_recursive(start,left-1);
        quick_sort_recursive(left+1, end);
    }

    //交换元素
    private void Swap(int x, int y){
        int temp = arr[x];
        arr[x] = arr[y];
        arr[y] = temp;
    }

}

评价:

选择排序

首先在未排序序列中找到最大(小)元素,存放到排序序列中的起始位置,然后,再从剩余未排序元素中继续寻找最大(小)元素,然后放到已排序序列的末尾。以此类推,直到所有元素排序完毕。

实现如下:

private static void selection_sort(int[] arr){
    int i,j,min,temp,len = arr.length;
    for (i = 0; i < len - 1; i ++){
            //记录当前元素
        min = i;
            //获取到未排序的序列中找到最小元素的位置
        for (j = i + 1; j < len; j ++)
            if (arr[min] > arr[j])
                min = j;
        //将最小的元素放在起始位置
        temp = arr[i];
        arr[i] = arr[min];
        arr[min] = temp;
    }
}

评价:

堆排序

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

public class HeapSort {
    private int[] arr;

    public HeapSort(int[] arr){
        this.arr = arr;
    }

    //进行排序
    public void sort(){
        //建立最大堆
        buildMaxHeap();

        //移除顶点,并调整堆顺序
        for (int i = arr.length - 1; i > 0; i --){
            //将顶点与最后的元素(最小值)交换
            swap(i,0);
            //然后调整堆顺序
            maxHeapify(0,i);
        }
    }

    private void swap(int i , int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    //建立最大堆,递归实现
    private void maxHeapify(int index, int len){
        //默认父节点为最大值
        int max = index;
        //获取左右孩子节点位置
        int left = (index * 2) + 1;
        int right = left + 1;
        //若左孩子大于父亲,则赋值左孩子
        if (left < len && arr[max] < arr[left])
            max = left;
        //若右孩子大于父亲,则赋值右孩子
        if (right < len && arr[max] < arr[right])
            max = right;
        //若需要更新父节点,则交换,并调整
        if (max != index){
            swap(index, max);
            maxHeapify(max,len);
        }
    }

    //建立最大堆
    private void buildMaxHeap(){
        //设置根节点位置
        int parent = arr.length/2 - 1;
        //从根开始创建堆
        for (int i = parent; i >= 0; i --){
            maxHeapify(i,arr.length);
        }
    }

    private  void printArray(int[] a){
        for (int i = 0; i < a.length; i ++){
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args){
        int[] arr = {81,94,11,96,12,35,17,95,28,58,41,75,15};
        System.out.println("Before sort:");
        HeapSort hs = new HeapSort(arr);
        hs.printArray(arr);
        hs.sort();
        System.out.println("After heapSort sort:");
        hs.printArray(arr);
    }

}

输出结果:
Before sort:
81 94 11 96 12 35 17 95 28 58 41 75 15 
After heapSort sort:
11 12 15 17 28 35 41 58 75 81 94 95 96 
归并排序

将数组划分为若干个部分进行排序,再将这些排序好的部分合并

实现过程:

归并排序

实现方法:

/**
 * 实现归并排序
 * @param arr 原始数组
 * @param rs 结果数组
 * @param start 开始位置
 * @param end 结束位置
 */
private static void merge_sort_recursive(int[] arr, int[] rs, int start, int end){
    if (start >= end)   return;
        //划分为两段,并分别设置这两段的始末位置
    int len = end - start;
    int mid = len / 2 + start;
    int s1 = start, e1 = mid;
    int s2 = mid + 1, e2 = end;
        //对这两段分别进行递归操作,划分数组
    merge_sort_recursive(arr,rs,s1,e1);
    merge_sort_recursive(arr,rs,s2,e2);
        //进行合并数组
    int k = start;
        //从两个划分的数组中选取较小的数放入结果数组中
    while (s1 <= e1 && s2 <= e2)
        rs[k++] = arr[s1] < arr[s2] ? arr[s1++] : arr[s2++];
        //对于未排完的,直接放入结果数组中
    while (s1 <= e1)
        rs[k++] = arr[s1++];
    while (s2 <= e2)
        rs[k++] = arr[s2++];
        //赋值给原始数组
    for (k= start; k <=end; k++)
        arr[k] = rs[k];
}
上一篇下一篇

猜你喜欢

热点阅读