码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构:排序算法

时间:2016-07-15 21:37:49      阅读:310      评论:0      收藏:0      [点我收藏+]

标签:

排序算法

<<插入排序>>

*直接插入排序*

思想

每次取剩下的一个元素插入到已经有序的序列中.

代码

public static void InsertSort(int[] arr){
        if(arr == null || arr.length == 0){
            System.err.println("ERROR INPUT");
            return;
        }

        int n = arr.length;

        for(int i = 1; i < n; i++){

            int temp = arr[i];
            int j = i - 1;
            while(j >= 0 && temp < arr[j]){
                arr[j+1] = arr[j];
                j--;
            }

            arr[j+1] = temp;
        }
    }

算法分析

*最好情况下:每次循环,内层都不需要比较,只有外层循环的常量级操作,时间复杂度为O(n)
*最坏情况下:内层循环每次都要比较i次,故总的执行次数是:1+2+3+…+n=n*(n-1)/2,故时间复杂度为O(n2)
*最后平均时间复杂度为:O(n2)
*空间复杂度:O(1)

*折半插入排序*

思想

基本思想与直接插入是一样的,区别在于寻找插入位置的方法不同,折半插入排序是采用折半查找来寻找插入位置的.

代码

public static void halfInsertSort(int[] arr){
        if(arr == null || arr.length == 0){
            System.err.println("ERROR INPUT");
            return;
        }

        for(int i = 1; i < arr.length; i++){

            int temp = arr[i];

            int low = 0;
            int high = i - 1;
            int idx = -1;
            while(low <= high){
                int m = (low+high)/2;

                if(arr[m] < temp){
                    low = m+1;
                }else if(arr[m] > temp){
                    high = m-1;
                }else{
                    idx = m+1;
                    break;
                }
            }
            if(low > high){
                idx = high + 1;
            }

            for(int j = i-1; j >= idx; j--){
                arr[j+1] = arr[j];
            }

            arr[idx] = temp;
        }

    }

算法分析

*外层循环为n-1次,内层循环是折半查找,
*最好情况是:复杂度为O(logn).故总的时间复杂度为O(nlogn);最坏情况是O(n2);平均情况为O(n2).
*空间复杂度为:O(1)

*希尔排序(shellsort)*

希尔排序,又称缩小增量排序,其本质还是插入排序,只不过将待排序的序列按某种规则分为几个子序列,分别对这几个子序列进行直接插入排序.这个规则就是增量

思想

比如对序列:49, 38, 65, 97, 76, 13, 27, 49
先选择3为增量,则得到序列1:49, 97, 27;序列2:38,76, 49;序列3:65, 13
分别对这三个使用直接插入排序,序列1:27,49,97;序列2:38,49,76;序列3:13,65
将三个序列合并起来:27,38,13,49,49,65,97,76
这就是一趟希尔排序了.接下来,再也2(或1)为增量进行一趟希而排序

代码

算法分析

平均时间复杂度:O(nlogn)
空间复杂度:O(1)

<<交换排序>>

*冒泡排序*

思想

每次通过一系列的交换动作,将最大(或最小)的数字冒出来.终止条件是一趟排序过程中没有发生元素交换

代码

public static void BubbleSort(int[] arr){
        if(arr == null || arr.length == 0){
            System.err.println("Error input");
            return;
        }

        for(int i = arr.length-1; i >= 1; i--){

            boolean flag = false;
            for(int j = 0; j < i; j++){
                if(arr[j] > arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;

                    flag = true;
                }
            }

            if(flag == false){
                return;
            }
        }
    }

算法分析

时间复杂度:最好(n)最坏O(n2)平均O(n2)
空间复杂度:O(1)

*快速排序*

思想

>快速排序也是"交换"类的排序,它的基本思想是找出一个枢纽,使得在它左边的比它小,右边的比它大.

代码

public static void QuickSort(int[] arr, int l, int r){
        if(arr == null || arr.length == 0 || l < 0 || r >= arr.length){
            System.err.println("ERROR INPUT");
            return;
        }

        int i = l;
        int j = r;
        if(l < r){
            int temp = arr[l];
            while(i != j){
                while(j > i && arr[j] > arr[i]){
                    j--;
                }

                if(i < j){
                    arr[i] = arr[j];
                    i++;
                }


                while(j > i && arr[i] < arr[j]){
                    i++;
                }
                if(i < j){

                    arr[j] = arr[i];
                    j--;
                }

            }

            arr[i] = temp;
            QuickSort(arr, l, i-1);
            QuickSort(arr, i+1, r);
        }
    }

另外一个写法:

    public int Partition(char[] arr, int start, int end){
        if(arr == null || arr.length == 0 || start < 0 || end < 0){
            return -1;
        }

        int index = start + (int)(Math.random() * ((end - start) + 1));//随机选择一个作为标杆的数字


        //将标杆放在数组最后一位
//        System.out.println(arr.toString());
//        System.out.println(arr[index]);
//        System.out.println(arr[end]);
        char tmp = arr[index]; arr[index] = arr[end]; arr[end] = tmp;

        int small = start - 1;//small用来存储从右到左第一个小于标杆的数字的下标
        for(index = start; index < end; index++){
            if(arr[index] < arr[end]){//如果小于标杆
                small++;//更新第一个小的
                if(small != index){//如果当前遍历的不是第一个小的
                    tmp = arr[index];arr[index] = arr[small];arr[small] = tmp;//将当前遍历的数字放在第一个小的位置上

                }
            }
        }

        //由于small指示的是从右到左第一个小于标杆的,而此时标杆还放在数组最后,因此,应该将标杆放在small后面一位。
        small++;
        tmp = arr[small];arr[small] = arr[end]; arr[end] = tmp;

        return small;//返回位置为所选择的标杆最后的位置


    }

    public void QuickSort(char[] arr, int start, int end){

        if(start == end){
            return;
        }
        int index = Partition(arr, start, end);

        if(index > start){
            QuickSort(arr, start, index - 1);
        }
        if(index < end){
            QuickSort(arr, index + 1, end);
        }
    }

算法分析

时间复杂度:最好O(nlog2n),平均O(nlog2n),最坏:O(n2)
空间复杂度O(log2n)
快速排序是所有排序算法中最好的.

<<选择排序>>

简单选择排序

思路:

简单选择排序采用最简单的选择方式,从头至尾顺序扫描序列,找出最小的一个记录,和第一个记录交换,接着从剩下的记录中继续这种选择和交换,最终使序列有序.

代码:

    public static void SimpleSelectSort(int[] arr){

        if(arr == null || arr.length == 0){
            System.err.println("ERROR INPUT");
            return;
        }


        for(int i = 0; i < arr.length; i++){
            int temp = arr[i];

            int min = arr[i];
            int idx = i;
            for(int j = i; j < arr.length; j++){
                if(arr[j] < min){
                    min = arr[j];
                    idx = j;
                }
            }

            arr[idx] = temp;
            arr[i] = min;

        }
    }

算法分析:

时间复杂度:O(n2)
空间复杂度:O(1)

堆排序

思路:

将序列调整成一个堆.

代码:

/**
     * 本函数完成对在数组R[low]到R[high]范围内对在位置low上的结点进行调整
     * @param arr
     * @param low
     * @param high
     */
    public static void shift(int[] arr, int low, int high){
        if(arr == null || arr.length == 0){
            return;

        }

        int i = low;
        int j = 2 * i;//arr[j]是arr[i]的左孩子结点
        int temp = arr[i];
        while(j <= high){
            if(j < high && arr[j] < arr[j+1]){//若右孩子较大,则把j指向右孩子
                j++;                        //j变为2*i+1
            }

            if(temp < arr[j]){//将R[j]调整到双亲位置上
                arr[i] = arr[j];
                i = j;
                j = 2 * i;
            }else{
                break;//调整结束
            }
        }

        arr[i] = temp;//被调整结点的值放入最终位置
    }

    /**
     * 堆排序函数
     * @param arr
     */

    public static void heapSort(int[] arr){
        if(arr == null || arr.length == 0){//输入参数的非法性检查
            System.err.println("ERROR INPUT");
            return;
        }

        int i;
        int temp;
        int n = arr.length;

        for(i = n / 2; i >= 0; i--){//建立初始堆
            shift(arr, i, n-1);
        }

        for(i = n-1; i >= 1; i--){//进行n-1次循环完成堆排序
            temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            shift(arr, 0, i-1);//在减少了1个元素的无序序列中进行调整
        }
    }

算法分析:

时间复杂度:O(nlog2n)
空间复杂度:O(1)

归并排序

二路归并排序

思路

初始状态是每个元素是一个子序列,然后两两合并,形成了几个两个元素的子序列,....,依次合并下去,直到合并为一个有序序列.

代码

算法分析

时间复杂度:O(nlog2n)
空间复杂度:O(n)

基数排序

算法分析

时间复杂度:O(d(n+rd))
空间复杂度:O(rd)

排序算法的对比

时间复杂度:

"快些以O(nlog2n)的速度归队"
即快,希,归,堆都是O(nlog2n),其他都是O(n2),基数排序例外,是O(d(n+rd))

空间复杂度:

快排O(log2n)
归并O(n)
基数O(rd)
其他O(1)

稳定性

"心情不稳定,快些找一堆朋友聊天吧"
即不稳定的有:快,希,堆

其他性质

  1. 直接插入排序,初始基本有序情况下,是(n)
  2. 冒泡排序,初始基本有序情况下,是(n)
  3. 快排在初始状态越差的情况下算法效果越好.
  4. 堆排序适合记录数量比较大的时候,从n个记录中选择k个记录.
  5. 经过一趟排序,元素可以在它最终的位置的有:交换类的(冒泡,快排),选择类的(简单选择,堆)
  6. 比较次数与初始序列无关的是:简单选择与折半插入
  7. 排序趟数与原始序列有关的是:交换类的(冒泡和快排)

数据结构:排序算法

标签:

原文地址:http://blog.csdn.net/lilianforever/article/details/51906771

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!