【复习笔记】常用的八大排序算法再总结

作者: 谷青_vm | 来源:发表于2016-04-13 15:56 被阅读271次

    最近在复习之前看过的数据结构和算法,发现当时看的排序算法忘得差不多了,所以今天就把常用的八大排序算法的 核心代码 再次总结以下,忘记时看下就能够回忆起来。

    大部分来自 胡昭民 的《图解数据结构——使用Java》的读书笔记

    1.冒泡排序

    分为传统的,和改进版的。

        /**
         * 传统冒泡排序
         */
        private static void bubble(int[] data) {
            int size = data.length;//原始数组大小
            int tem; //临时变量
            for (int i = size-1;i>0;i--) {
                for (int j = 0;j<i;j++) {
                    //比较相邻两数,若第一数较大则交换
                    if (data[j] > data[j+1]) {
                        tem = data[j];
                        data[j] = data[j+1];
                        data[j+1] = tem;
                    }
                }
            }
        }
    

    下面是改进版的

        /**
         * 改进的冒泡排序,如果一次比较后没有交换 证明已排好序,直接跳出循环
         */
        private static void improvedbubble(int[] data) {
            int tem;  //临时变量
            int flag;  //判断是否有执行交换的动作
            int size = data.length;//原始数组大小
            for (int i = size-1;i>0;i--) {
                flag = 0;
                for (int j = 0;j<i;j++) {
                    //比较相邻两数,若第一数较大则交换
                    if (data[j] > data[j+1]) {
                        tem = data[j];
                        data[j] = data[j+1];
                        data[j+1] = tem;
                        flag++; //执行过交换 flag不为0
                    }
                }
                if (flag == 0) {
                    break;
                }
            }
        }
    

    2.选择排序

        /**
         * 选择排序
         * 例如N个数据要由大到小排序时,首先以第一个位置的数据,
         * 依次向2,3,4,N个位置的数据作比较,
         * 如果数据大于或等于其中一个位置,则两个位置的数据不变,
         * 若小于,则交换
         */
        private static void selectionSort (int[] data){
            int tem;  //临时变量
            int size = data.length;//原始数组大小
            for (int i = 0;i<size-1;i++) { //扫描size-1次
                for (int j = i+1;j<size;j++) {//由i+1比较,比较size-1次
                    if (data[i] > data[j]) {//比较第i及第j份元素
                        tem = data[i];
                        data[i] = data[j];
                        data[j] = tem;
                    }
                }
            }
        }
    

    3.插入排序

        /**
         * 插入排序
         * 是将数组中的元素,逐一与已排序好的数据作比较,
         * 再将该数组元素插入适当的位置。
         */
        private static void insertSort(int[] data) {
            int tem;  //临时变量
            int size = data.length;//原始数组大小
            int j;//定位比较的元素
            for (int i =1;i<size;i++) {//默认第一个元素已排好序,从第二个元素开始扫描,扫描size-1次
                tem = data[i];
                j = i-1; //将data[i] 与 它的前一位data[i-1] 比较
                while (j>=0 && tem<data[j]) { //若小于
                    data[j+1] = data[j]; //就把所有的元素往后推一个
                    j--;
                }
                data[j+1] = tem; //最小的元素 放到移动后的缺口处
            }
        }
    

    4.希尔排序

        /**
         * 希尔排序
         * D.L.Shell 在 1959年7月发明的一种排序
         * 时间复杂度达到O(n^1.5)
         * 有点像插入排序,将数据区分成特定间隔的几个小块,以插入排序法排完
         * 区块内的数据后再渐渐减少间隔距离
         */
        private static void shellSort(int[] data){
            int tem;  //临时变量
            int jmp;  //设定间隔位移量
            int size = data.length;//原始数组大小
            int j;//定位比较的元素
            jmp = size/2; //先以数组大小的一半作为间隔位移量
            while (jmp != 0) {
                for (int i = jmp;i<size;i++) {
                    tem = data[i];
                    j = i - jmp;
                    //下面就是插入排序了
                    while (j>=0 && tem < data[j]) {
                        data[j+jmp] = data[j];
                        j = j - jmp;
                    }
                    data[jmp + j] = tem;
                }
                jmp = jmp/2;  //控制循环数
            }
        }
    

    5.快速排序

        /**
         * 快速排序
         * 假设有n个记录R1,R2,R3...Rn,键值为k1,k2,k3...kn
         * 1.取k为第一个键值
         * 2.由左向右找出一个键值Ki 使得Ki>K
         * 3.由右向左找出一个键值Kj 使得Kj<K
         * 4.若i<j 则Ki与Kj交换,并继续步骤2
         * 5.若i>=j 则将K与Kj交换,并以j为记住将数据分为左右两部分,
         * 以递归方式分别对左右两边进行排序,直至完成排序
         */
        private static void quickSort2(int[] data,int left,int right) {
            int tem;//临时变量
            int lf_idx;//从左向右移动的键
            int rg_idx;//从右向左移动的键
            //第一个键值为data[left]
            if (left < right) {
                lf_idx = left+1;
                rg_idx = right;
                //开始排序
                while (true) {
                    for (int i = left+1;i<=right;i++) {//2.由左向右找出一个键值>data[left]者
                        if (data[i] >= data[left]) {
                            lf_idx = i;
                            break;
                        }
                        lf_idx++;
                    }
                    for (int j = right;j>=left+1;j--) {//3.由右向左找出一个键值<data[left]者
                        if (data[j] <= data[left]) {
                            rg_idx = j;
                            break;
                        }
                        rg_idx--;
                    }
                    if (lf_idx < rg_idx) {//4.若lf_idx < rg_idx
                        tem = data[lf_idx]; //则交换data[lf_idx]和data[rg_idx]
                        data[lf_idx] = data[rg_idx];
                        data[rg_idx] = tem;
                    }else {
                        break;
                    }
                }
                //整理
                if (lf_idx >= rg_idx) {  //5-1 若lf_idx >= rg_idx
                    tem = data[left]; //则交换 data[left] 和 data[rg_idx]
                    data[left] = data[rg_idx];
                    data[rg_idx] = tem;
                    //5-2 并以rg_idx为基准点分成两半,递归排序
                    quickSort2(data,left,rg_idx-1);
                    quickSort2(data,rg_idx+1,right);
                }
            }
        }
    

    6.堆排序

    堆排序参考了网上这篇文章
    http://www.cnblogs.com/ttltry-air/archive/2012/08/03/2621962.html
    里面有动画,大家可以去看下,很好看。
    核心代码在下面

        /**
         * 堆排序
         *1.建初始堆:将R[1..n]构造为初始堆;
         *2.堆调整:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆。
         */
        public static void buildHeap(int a[]) {
            int heapSize = a.length;
            int filter = heapSize / 2;
            // i从第一个非叶子结点开始
            for (int i = filter - 1; i >= 0; i--) {
                heapAdjust(a, i, heapSize);
            }
        }
    
        // 已知H.r[i...heapSize]中记录的关键字除H.r[i]外,均满足最大堆结构
        public static void heapAdjust(int arr[], int i, int heapSize) {
            // 当前待调整的元素
            int tmp = arr[i];
            // 该元素的左孩子
            int index = 2 * i + 1;
            while (index < heapSize) {
                // 如果右孩子大于左孩子,则index+1,即交换右孩子和双亲节点
                if (index + 1 < heapSize && arr[index] < arr[index + 1]) {
                    index = index + 1;
                }
                if (arr[i] < arr[index]) {
                    arr[i] = arr[index];// 交换孩子和双亲节点
                    i = index;// 重新赋初值
                    index = 2 * i + 1;
                }
                else {
                    break;// 已经是最大堆
                }
                arr[i] = tmp;// 把双亲值赋给孩子节点
            }
        }
    
        public static void heapSort(int a[]) {
            int heapSize = a.length;
            for (int i = heapSize - 1; i > 0; i--) {
                // 交换堆顶和最后一个元素
                int tmp = a[0];
                a[0] = a[i];
                a[i] = tmp;
                // 在heapSize范围内根结点的左右子树都已经是最大堆,所以只需看新交换的堆顶元素是否满足最大堆结构即可。
                // 将H.r[0...i]重新调整为最大堆
                heapAdjust(a, 0, i);
            }
        }
    

    7.归并排序

    归并排序,我觉得维基百科讲的就很不错,大家可以看看维基百科的讲解https://zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F#Java
    下面是java迭代版的核心代码

        /**
         * 归并排序
         */
        public static int[] merge_sort(int[] arr) {
            int len = arr.length;
            int[] result = new int[len];
            int block, start;
    
            for(block = 1; block < len ; block *= 2) {
                for(start = 0; start <len; start += 2 * block) {
                    int low = start;
                    int mid = (start + block) < len ? (start + block) : len;
                    int high = (start + 2 * block) < len ? (start + 2 * block) : len;
                    //两个块的起始下标及结束下标
                    int start1 = low, end1 = mid;
                    int start2 = mid, end2 = high;
                    //开始对两个block进行归并排序
                    while (start1 < end1 && start2 < end2) {
                        result[low++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
                    }
                    while(start1 < end1) {
                        result[low++] = arr[start1++];
                    }
                    while(start2 < end2) {
                        result[low++] = arr[start2++];
                    }
                }
                int[] temp = arr;
                arr = result;
                result = temp;
            }
            result = arr;
            return result;
        }
    

    8.基数排序

        /**
         * 基数排序
         * 假设每个数位数不超过3位
         */
        private static void radixSort(int[] data) {
            int size = data.length;
            int k;
            int n;
            int m;
            for (n = 1;n<=100;n = n*10) { //n为基数 从个位开始排序
                //设定暂存数组,[0~9位数][数据个数],所有内容均为0
                int[][] tem = new int[10][100];
                for (int i=0;i<size;i++) {   //比较所有数据
                    m = (data[i]/n)%10;   //m为n位数的值
                    tem[m][i] = data[i]; //把data[i]的值暂存在tem里
                }
                k=0;
                for (int i =0;i<10;i++) {
                    for (int j=0;j<size;j++) {
                        if (tem[i][j] != 0) {  //一开始设定tem={0},所以不为0证明里面有数
                            //把data暂存在tem里的值 放回data[]里
                            data[k] = tem[i][j];
                            k++;
                        }
                    }
                }
            }
        }
    
    

    附上一张 各种排序的总结

    排序总结

    参考资料

    大部分来自 胡昭民 的《图解数据结构——使用Java》的读书笔记
    一部分来自大神网友的博客
    https://zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F#Java
    http://www.cnblogs.com/ttltry-air/archive/2012/08/03/2621962.html
    http://www.cnblogs.com/rollenholt/archive/2012/04/15/2450175.html
    http://blog.csdn.net/morewindows/article/details/6709644

    相关文章

      网友评论

        本文标题:【复习笔记】常用的八大排序算法再总结

        本文链接:https://www.haomeiwen.com/subject/qhawlttx.html