排序算法学习

排序算法学习

=========================

  排序算法众多,我这里主要学习了比较常见的几种排序算法,直接以代码形式给出,理解就以注释的形式给出了。每次运行时需要把前面的一个排序注释掉,因为数组传值时是传引用。经过前面的排序已经有序了,在运行后面的排序时就没有效果了。

package com.zcyfover.interview;

/**
 * Created by zcy-fover on 2016/8/24.
 */

import java.util.Arrays;

/**
 * 学习排序的各种算法
 */
public class Sort {

    public static void main(String[] args) {
        final int[] testArray = new int[]{5, 1, 43, 23, 24, 67, 6, 3, 788, 32};
        Sort sort = new Sort();
//        sort.bubbleSort(testArray);
//        sort.selectSort(testArray);
//        sort.insertSort(testArray);
//        System.out.print("QuickSort Result: ");
//        sort.quickSort(testArray, 0, testArray.length - 1);
//        System.out.print("MergeSort Result: ");
//        sort.mergeSort(testArray, 0, testArray.length-1);
//        sort.binaryInsertSort(testArray);
//        sort.shellSort(testArray, testArray.length);
        for (int i = 0; i < testArray.length; i++){
            System.out.print(testArray[i] + " ");
        }
    }

    /**
     * 冒泡排序:两两比较关键字,每次讲较大的关键字进行“下沉”处理;每一次排序都会使有序区增加一个气泡,
     *          经过n-1次后,有序区就有n-1个气泡,此时有序区的气泡的值总是大于无序区的,所以冒泡排序至少要经过
     *          n-1次排序。
     * 改进:在无序区的某一次排序中要是没有了气泡的交换,说明这个序列已经是有序得了。不用再执行后面的排序了,此时
     *      需要一个交换的标志来监督程序的执行。每次排序开始前现将exchange置为false,如果在这一趟排序中发生了交换
     *      则把exchange改编为true,如果没有进行交换说明在无序区的序列已经全部有序了,程序可以结束了。具体实现如下
     * 算法分析:
     *          (1)最好时间复杂度:
     *              若文件初始状态有序,即通过一次扫描即可结束排序,关键字的比较次数C和记录移动次数M都达到最小Cmin=n-1;Mmin=0
     *          (2)最坏时间复杂度:
     *              若文件是倒序,要进行n-1次排序,每次都要进行n-i次关键字的比较(1< = i <= n-1),且每次都必须移动记录三次以达到交
     *              换位置的目的,在这种情况下比较和交换次数都达到最大值Cmax=n(n-1)/2=O(n^2),Mmax=3n(n-1)/2=O(n^2);
     *          (3)平均时间复杂度:
     *              在平常情况下,很少会有最好和最坏的情况出现,一般不一定会进行n-1次,但是由于他的记录移动次数较多,故平均时间性能
     *              比直接插入排序要差很多。O(n^2)
     *          (4)冒泡排序时就地排序,所以它是稳定的。
     * @param source
     */
    public void bubbleSort(int[] source) {
        boolean exchange;
        for (int i = source.length - 1; i > 0; i--){
            exchange = false;
            for(int j = 0; j < i; j++){
                if (source[j] > source[j + 1]){
                    int temp = source[j + 1];
                    source[j + 1] = source[j];
                    source[j] = temp;
                    exchange = true;
                }
            }
            if (!exchange){
                break;
            }
        }
        System.out.print("BubbleSort Result: ");
    }

    /**
     * 选择排序
     * 算法思想:
     *        (1)从待排序序列中找到最小的元素;
     *        (2)将最小元素存放到未排序序列的起始位置;
     *        (3)从余下的n-i个元素中继续寻找最小元素
     * 算法分析:
     *        时间复杂度:假设排序序列有N个元素,比较次数总是在n(n-1)/2之间;
     *                  移动次数和序列的初始化顺序有关,当序列正序时,移动次数最小为0;当序列倒序时,移动次数最大为3n(n-1)/2;
     *                  综上,选择排序的时间复杂度为:O(n^2)
     *        空间复杂度:每次交换时需要占用一个临时空间,空间复杂度为O(1)
     * 稳定性:不稳定。比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面
     * @param source
     */
    public void selectSort(int[] source){
        for (int i = 0; i < source.length; i++){
            for (int j = i + 1; j < source.length; j++){
                if (source[i] > source[j]){
                    int temp = source[j];
                    source[j] = source[i];
                    source[i] = temp;
                }
            }
        }
        System.out.print("SelectSort Result: ");
    }

    /**
     * 插入排序:
     *        算法思想:
     *              (1)从第一个元素开始,可以认为他已经是有序的
     *              (2)取出下一个元素,在已经排序的元素序列中从后向前扫描
     *              (3)如果该元素大于新元素,则将新元素与该元素交换位置
     *              (4)重复步骤3,直到新元素大于或等于已排序的元素
     *              (5)此时新元素已经找到自己合适的位置了
     *              (6)重复步骤2
     *        时间复杂度:
     *                如果目标是把n个元素的序列升序排列:
     *                  最好的情况:序列已经是升序,此时只需要进行n-1次比较即可,时间复杂度为O(n);
     *                  最坏的情况:序列是反序,此时需要进行n(n-1)/2次比较,插入操作为比较操作次数加n-1次,
     *                            此时复杂度为O(n^2)
     *        空间复杂度:O(1)
     *        稳定性:稳定
     *        插入排序算法不适合于数据量比较大的排序应用,但如果数据量比较小的话,例如千级可以选用插入排序
     * @param source
     */
    public void insertSort(int[] source){
        for (int i = 1; i < source.length; i++){
            for (int j = i; (j > 0) && (source[j] < source[j - 1]); j--){
                int temp = source[j];
                source[j] = source[j - 1];
                source[j -1] = temp;
            }
        }
        System.out.print("InsertSort Result: ");
    }

    /**
     * 快速排序
     * 算法思想:
     *     分治法思想:快速排序采用分治的策略,分治法是将原问题分解为若干个规模更小的但结构与原问题相似的子问题,
     *               递归的解这些这些小问题,最后将子问题的解合并为原问题的解。
     *     快速排序算法思想:设当前待排序的无序区为R[low...high]
     *              (1)分解:在R[low...high]中任选一个记录作为基准(Pivot),一次基准将当前无序区划分为左、右
     *                        两个较小的子区间R[low...Pivot-1]和P[Pivot+1...high],并使左边子区间中所有的记
     *                        录的关键字均小于或等于基准记录的关键字pivot.key,右边子区间的中所有的记录关键字均
     *                        大于或等于基准记录pivot.key,而基准记录pivot则位于正确的位置上(pivotPos),无需
     *                        参加后续的排序。划分的关键是要求出基准记录所在的位置pivotPos。划分可以简单的表示为
     *                        R[low...pivotPos-1].keys <= R[pivotPos].key <= R[pivotPos+1...high].keys
     *                        其中必须满足low= pivot){//从后向前扫描,如果j位置的值比基准位置pivot的值大,则将j指
                    j--;                            //针继续向前移动,同时保证i < j
                }
                if (i < j){ //在j指针前移的时候,如果source[j]的值小于pivot,则需要将source[i]的值和source[j]的
                    source[i] = source[j]; //值交换
                    i++;    //将i指针后移以为,下面开始从前向后(从低位向高位)扫描
                }   //此时基准位置移到了j上
                while (i < j && source[i] <= pivot){
                    i++;    //低位到高位扫描,如果source[i]B0则C0=B0,B的指向后移一位为B1
     *          (3)A0和B1比较,A0B1则C2=B1,B的指向后移一位为B2
     *          (5)A1和B2比较,A1 temp){
                    high = mid - 1;
                } else{
                    low = mid + 1;
                }
            }
            for (j = i - 1; j > high; j--){
                source[j+1] = source[j];
            }
            source[high + 1] = temp;
        }
        System.out.println("BinaryInsertSort: ");
    }

    /**
     * 希尔排序
     * 基本思想:先对数据分组,然后对每一组数据进行排序,在每一组数据都有序之后,就可以对所有的分组利用插入排序进行最后一次排序。
     *          这样就减少了数据交换得次数
     * 算法思想:先去一个小于n的整数d1作为第一个增量,把文件的全部记录分成di个组,所有距离为di的倍数的记录放在同一个组中。现在
     *          各个组内进行直接插入排序;然后取第二个增量d2= 0 && pointer <= index){
                    source[pointer + dataLength] = source[pointer];
                    //计算下一个欲进行处理的位置
                    pointer = pointer - dataLength;
                    change = true;
                    if (pointer < 0 || pointer > index){
                        break;
                    }
                }
                //与最后的数值交换
                source[pointer + dataLength] = temp;
                if(change){
                    //打印目前排序结果
                    System.out.println("排序中: ");
                    for (k = 0; k < index; k++){
                        System.out.printf("%6s", source[k]);
                    }
                    System.out.println(" ");
                }
            }
            dataLength = dataLength / 2;
        }
    }
}

你可能感兴趣的:(数据结构,排序算法)