Java排序算法以及算法改进总结(冒泡、选择、插入、归并、快速排序)

算法复习,代码是最好的说明!

一、冒泡排序:

算法:

比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n)O(n^2)O(1)稳定

代码:

 /**
     * 冒泡排序
     * @param array
     */
    void bubbleSort_1(int[] array){
        for (int i = array.length-1; i >0 ; i--) {
            for (int j = 0; j <i ; j++) {
                if (array[j]>array[j+1]){
                    swap(array,j,j+1);
                }
            }
        }
    }

    /**
     * 冒泡排序改进,标志某一趟排序过程中是否有数据交换,如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序,避免不必要的比较过程
     * @param array
     */
    void bubbleSort_2(int[] array){
        boolean isSwaped;
        for (int i = array.length-1; i >0 ; i--) {
            isSwaped = false;
            for (int j = 0; j <i ; j++) {
                if (array[j]>array[j+1]){
                    swap(array,j,j+1);
                    isSwaped = true;
                }

            }
            if (!isSwaped)
                break;
        }

    }

    /**
     * 冒泡排序改进,设置一个pos指针,pos后面的数据在上一轮排序中没有发生交换,下一轮排序时,就对pos之后的数据不再比较
     * @param array
     */
    void bubbleSort_3(int[] array){
        int end = array.length - 1;
        while (end>0) {
            int pos = 1;
            for (int j = 1; j <=end; j++) {
                if (array[j-1] > array[j]) {
                    swap(array, j-1, j);
                    pos = j;
                }
            }
            end = pos - 1;

        }
    }

    /**
     * 鸡尾酒排序,也叫定向冒泡排序,是冒泡排序的一种改进。此算法与冒泡排序的不同处在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能。
     * @param array
     */
    void bubbleSort_4(int[] array){
        int left = 0;
        int right = array.length-1;
        while (left < right){
            for (int i = left; i <right ; i++) {
                if (array[i] > array[i+1]) swap(array,i,i+1);
            }
            right--;

            for (int i = right; i >left ; i--) {
                if (array[i] < array[i-1]) swap(array,i,i-1);
            }
            left++;
        }
    }

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


二、选择排序:

算法:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n^2)O(n^2)O(1)不稳定

代码:

/**
     * 选择排序
     * @param array
     */
    void selectionSort_1(int[] array){

        for (int i = 0; i <array.length-1 ; i++) {
            int min = i;

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

            }

            if (min!=i) swap(array,min,i);

        }
    }

    /**
     * 选择排序改进,每趟排序确定两个最值——最大值与最小值,这样就可以将排序趟数缩减一半。
     * @param array
     */
    void selectionSort_2(int[] array){
        int left = 0;
        int right = array.length-1;

        while (left<right){
            int min = left;
            int max = right;

            for (int i = left; i <=right; i++) {
                if (array[i]<array[min]) min = i;
                if (array[i]>array[max]) max = i;
            }

            if (min!=left) swap(array,min,left);
            if (max!=right&&max!=left) swap(array,max,right);

            left++;
            right--;

        }

    }

三、插入排序:

1、直接插入排序:

算法:

从第一个元素开始,该元素可以认为已经被排序
取出下一个元素,在已经排序的元素序列中从后向前扫描
如果该元素(已排序)大于新元素,将该元素移到下一位置
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
将新元素插入到该位置后
重复步骤2~5

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n)O(n^2)O(1)稳定

代码:

   /**
     * 插入排序,写法一
     * @param array
     */
    void insertionSort_1(int[] array){
        for (int i = 1; i < array.length; i++) {
            int get = array[i];
            int j = i-1;
            while (j>=0&&array[j]>get){
                array[j+1] = array[j];
                j--;
            }
            array[j+1] = get;

        }
    }

    /**
     * 插入排序,写法二
     * @param array
     */
    void insertionSort_2(int[] array){
        for (int i = 1; i < array.length; i++) {
            for (int j = i; j >0 ; j--) {
                if (array[j]<array[j-1]) swap(array,j,j-1);
                else break;
            }

        }
    }


2、二分插入排序:

算法:

利用二分法的思想对插入排序进行改进。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(nlogn)O(n^2)O(1)不稳定

代码:

/**
     * 插入排序改进二分法插入
     * @param array
     */
    void insertionSortDichotomy(int[] array){
        for (int i = 1; i < array.length; i++) {
            int get = array[i];
            int left = 0;
            int right = i - 1;
            while (left<=right){
                int mid = (left+right)/2;
                if (array[mid]<get)
                    left = mid + 1;
                else
                    right = mid - 1;

            }

            for (int j = i-1; j >=left; j--) {
                array[j+1] = array[j];
            }
            array[left] = get;

        }

    }


3、希尔插入排序:

算法:

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

分析:

平均最好最坏辅助存储稳定性
O(n^2)O(n^1.3)O(n^2)O(1)不稳定

代码:

/**
     * 插入排序改进希尔排序,写法一
     * @param array
     */
    void shellSort_1(int[] array){

        for (int gap = array.length/2; gap >0 ; gap/=2) {

            for (int i = 0; i < gap; i++) {

                for (int j = i+gap; j < array.length; j+=gap) {
                    int get = array[j];
                    int k = j-gap;

                    while (k>=0&&array[k]>get){
                        array[k+gap]=array[k];
                        k-=gap;
                    }
                    array[k+gap] = get;

                }

            }

        }
    }

    /**
     * 插入排序改进希尔排序,写法二
     * @param array
     */
    void shellSort_2(int[] array){

        for (int gap = array.length/2; gap >0 ; gap/=2) {

            for (int i = 0; i < gap; i++) {

                for (int j = i+gap; j < array.length; j+=gap) {

                    for (int k = j; k >=gap ; k-=gap) {
                        if (array[k]<array[k-gap]) swap(array,k,k-gap);
                        else break;

                    }

                }
                
            }
            
        }
    }


四、归并排序:

算法:

归并排序的实现分为递归实现与非递归(迭代)实现。归并排序算法主要依赖归并(Merge)操作,归并操作指的是将两个已经排序的序列合并成一个序列的操作
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
设定两个指针,最初位置分别为两个已经排序序列的起始位置
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针到达序列尾
将另一序列剩下的所有元素直接复制到合并序列尾

分析:

平均最好最坏辅助存储稳定性
O(nlogn)O(nlogn)O(nlogn)O(n)稳定

代码:

/**
     * 将两个已经排序的序列合并成一个序列的操作
     * @param array
     * @param left
     * @param mid
     * @param right
     */
    void merge(int[] array,int left,int mid,int right){
        int[] temp = new int[right-left+1];
        int index = 0;
        int i = left;
        int j = mid+1;

        while (i<=mid&&j<=right)
            temp[index++] = array[i] <= array[j] ? array[i++] : array[j++];



        while (i<=mid)
            temp[index++] = array[i++];
        
        while (j<=right)
            temp[index++] = array[j++];

        for (int k = 0; k <right-left+1; k++)
            array[left+k] = temp[k];



    }

    /**
     * 递归实现
     * @param array
     * @param left
     * @param right
     */
    void MergeSortRecursion(int[] array,int left,int right){
        if (left==right) return;

        int mid = (left+right)/2;
        MergeSortRecursion(array,left,mid);
        MergeSortRecursion(array,mid+1,right);

        merge(array,left,mid,right);
    }

    /**
     * 非递归实现
     * @param array
     */
    void MergeSortIteration(int[] array){
        int left,mid,right;

        for (int i = 1; i < array.length; i*=2) {
            left = 0;
            while (left+i < array.length){
                mid = left + i - 1;
                right = mid + i < array.length ? mid + i : array.length - 1;
                merge(array,left,mid,right);
                left = right + 1;

            }

        }
    }

五、快速排序:

算法:

从序列中挑出一个元素,作为"基准"(pivot)。
把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。

分析:

平均最好最坏辅助存储稳定性
O(nlogn)O(nlogn)O(n^2)O(nlogn)不稳定

代码:

 /**
     *
     * @param array
     * @param left
     * @param right
     * @return
     */
    int partition_1(int[] array, int left, int right){
        int pivot = array[right];
        int tail = left-1;

        for (int i = left; i < right; i++) {
            if (array[i] < pivot) swap(array,++tail,i);

        }

        swap(array,++tail,right);
        return tail;

    }

    /**
     * 改进将pivot的选择随机化,不再是固定选择左端点,或采用三支取中
     * @param array
     * @param left
     * @param right
     * @return
     */
    int partition_2(int[] array, int left, int right){
        swap(array,right, left+new Random().nextInt(right-left+1));
        int pivot = array[right];
        int tail = left-1;

        for (int i = left; i < right; i++) {
            if (array[i] < pivot) swap(array,++tail,i);

        }

        swap(array,++tail,right);
        return tail;

    }

    /**
     * 改进使用两个索引i和j,分别从左右两端进行扫描,i扫描到大于等于pivot的元素就停止,j扫描到小于等于pivot的元素也停止,交换两个元素,持续这个过程直到两个索引相遇,此时的pivot的位置就落在了j,然后交换pivot和j的位置
     * @param array
     * @param left
     * @param right
     * @return
     */
    int partition_3(int[] array, int left, int right){
        swap(array,right, left+new Random().nextInt(right-left+1));
        int pivot = array[right];


        int i = left - 1;
        int j = right;

        while (true){
            do {
                i++;
            }while (i<=right&&array[i]<pivot);

            do {
                j--;
            }while (j>=left&&array[j]>pivot);

            if (j < i) break;

            swap(array,i,j);
        }

        swap(array,++j,right);

        return j;

    }

    /**
     *
     * @param array
     * @param left
     * @param right
     */
    void quickSort(int[] array, int left, int right){
        if (left>=right) return;


        int pivot_index = partition_3(array,left,right);
        quickSort(array,left,pivot_index-1);
        quickSort(array,pivot_index+1,right);

    }


参考链接:

 http://www.cnblogs.com/eniac12/p/5329396.html#s5

 http://blog.csdn.net/morewindows/article/details/6668714

 http://blog.csdn.net/hguisu/article/details/7776068

http://www.blogjava.net/killme2008/archive/2010/09/08/quicksort_optimized.html

如有错误,欢迎纠正!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值