• 选择排序


    选择排序有简单选择排序,堆排序

    简单选择排序:

    import java.util.Arrays;
    import java.util.Random;
    
    public class Main {
        public static void main(String[] args) throws InterruptedException {
            int[] array = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3};
            System.out.println(Arrays.toString(array));
            selectionSort(array);
            System.out.println(Arrays.toString(array));
        }
    
        //选择排序
        public static void selectionSort(int[] array){
            int minPoint;  //存储最小元素的小标
            int len = array.length;
            int temp;
            int counter = 1;
    
            for(int i=0;i<len-1;i++){
    
                minPoint= i;
                for(int j=i+1;j<=len-1;j++){  //每完成一轮排序,就确定了一个相对最小元素,下一轮排序只对后面的元素排序
                    if(array[j]<array[minPoint]){  //如果待排数组中的某个元素比当前元素小,minPoint指向该元素的下标
                        minPoint= j;
                    }
                }
    
                if(minPoint!=i){  //如果发现了更小的元素,交换位置
                    temp= array[i];
                    array[i]= array[minPoint];
                    array[minPoint]= temp;
                }
    
                System.out.print("第"+counter+"轮排序结果:");
                display(array);
                counter++;
            }
        }
    
        private static void display(int[] array){
            System.out.println(Arrays.toString(array));
        }
    }
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3]
    第1轮排序结果:[-3, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, 9]
    第2轮排序结果:[-3, -2, 7, 6, 5, 4, 3, 2, 1, 0, -1, 8, 9]
    第3轮排序结果:[-3, -2, -1, 6, 5, 4, 3, 2, 1, 0, 7, 8, 9]
    第4轮排序结果:[-3, -2, -1, 0, 5, 4, 3, 2, 1, 6, 7, 8, 9]
    第5轮排序结果:[-3, -2, -1, 0, 1, 4, 3, 2, 5, 6, 7, 8, 9]
    第6轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    第7轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    第8轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    第9轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    第10轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    第11轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    第12轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    View Code

    简单选择排序,就是一次遍历选择最小的,然后与第一位进行交换,然后再剩下的里面再次进行查找最小的,再次交换........

    选择排序与冒泡排序一样,需要进行N*(N-1)/2次比较,但是只需要N次交换,当N很大时,交换次数的时间影响力更大,所以选择排序的时间复杂度为O(N2)

    虽然选择排序与冒泡排序在时间复杂度属于同一量级,但是毫无疑问选择排序的效率更高,因为它的交换操作次数更少,而且在交换操作比比较操作的时间级大得多时,选择排序的速度是相当快的。

    优化方案:一次遍历查找出最小跟最大值,分别与第一位,最后一位进行交换,然后在剩下的数组里面再次进行查找最大,最小........

    import java.util.Arrays;
    import java.util.Random;
    
    public class Main {
        public static void main(String[] args) throws InterruptedException {
            int[] array = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3};
            System.out.println(Arrays.toString(array));
            selectionSort_improvement(array);
            System.out.println(Arrays.toString(array));
        }
        
        //选择排序改进版
        public static void selectionSort_improvement(int[] array){
            int minPoint;  //存储最小元素的小标
            int maxPoint;  //存储最大元素的小标
            int len = array.length;
            int temp;
            int counter = 1;
    
            for(int i=0;i<len/2;i++){
    
                minPoint= i;
                maxPoint= i;
                for(int j=i+1;j<=len-1-i;j++){  //每完成一轮排序,就确定了两个最值,下一轮排序时比较范围减少两个元素
                    if(array[j]<array[minPoint]){  //如果待排数组中的某个元素比当前元素小,minPoint指向该元素的下标
                        minPoint= j;
                        continue;
                    }else if(array[j]>array[maxPoint]){  //如果待排数组中的某个元素比当前元素大,maxPoint指向该元素的下标
                        maxPoint= j;
                    }
                }
    
                if(minPoint!=i){  //如果发现了更小的元素,与第一个元素交换位置
                    temp= array[i];
                    array[i]= array[minPoint];
                    array[minPoint]= temp;
    
                    //原来的第一个元素已经与下标为minPoint的元素交换了位置
                    //如果之前maxPoint指向的是第一个元素,那么需要将maxPoint重新指向array[minPoint]
                    //因为现在array[minPoint]存放的才是之前第一个元素中的数据
                    if(maxPoint== i){
                        maxPoint= minPoint;
                    }
                }
                if(maxPoint!=len-1-i){  //如果发现了更大的元素,与最后一个元素交换位置
                    temp= array[len-1-i];
                    array[len-1-i]= array[maxPoint];
                    array[maxPoint]= temp;
                }
                System.out.print("第"+counter+"轮排序结果:");
                display(array);
                counter++;
            }
        }
    
        private static void display(int[] array){
            System.out.println(Arrays.toString(array));
        }
    }
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3]
    第1轮排序结果:[-3, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, 9]
    第2轮排序结果:[-3, -2, 7, 6, 5, 4, 3, 2, 1, 0, -1, 8, 9]
    第3轮排序结果:[-3, -2, -1, 6, 5, 4, 3, 2, 1, 0, 7, 8, 9]
    第4轮排序结果:[-3, -2, -1, 0, 5, 4, 3, 2, 1, 6, 7, 8, 9]
    第5轮排序结果:[-3, -2, -1, 0, 1, 4, 3, 2, 5, 6, 7, 8, 9]
    第6轮排序结果:[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    View Code

    堆排序:

    这个版本感觉不太好

    import java.util.Arrays;
    import java.util.Random;
    
    public class Main {
        static  int[] array = {7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2,10,-3};
        public static void main(String[] args) throws InterruptedException {
    
            System.out.println(Arrays.toString(array));
            heapSort();
            System.out.println(Arrays.toString(array));
        }
    
    
        //堆排序
        public static void heapSort(){
            buildHeap();
            System.out.println("建堆:");
            printTree(array.length);
    
            int lastIndex = array.length-1;
            while(lastIndex>0){
                swap(0,lastIndex);  //取出堆顶元素,将堆底放入堆顶。其实就是交换下标为0与lastIndex的数据
                if(--lastIndex == 0) break;  //只有一个元素时就不用调整堆了,排序结束
                adjustHeap(0,lastIndex);  //调整堆
    
                System.out.println("调整堆:");
                printTree(lastIndex+1);
            }
    
        }
    
    
    
        /**
         * 用数组中的元素建堆
         */
        private static void buildHeap(){
            int lastIndex = array.length-1;
            for(int i= (lastIndex-1)/2;i>=0;i--){ //(lastIndex-1)/2就是最后一个元素的根节点的下标,依次调整每棵子树
                adjustHeap(i,lastIndex);  //调整以下标i的元素为根的子树
            }
        }
    
        /**
         * 调整以下标是rootIndex的元素为根的子树
         *@param rootIndex 根的下标
         *@param lastIndex 堆中最后一个元素的下标
         */
        private static void adjustHeap(int rootIndex,int lastIndex){
    
            int biggerIndex = rootIndex;
            int leftChildIndex = 2*rootIndex+1;
            int rightChildIndex = 2*rootIndex+2;
    
            if(rightChildIndex<=lastIndex){  //存在右子节点,则必存在左子节点
    
                if(array[rootIndex]<array[leftChildIndex] || array[rootIndex]<array[rightChildIndex]){ //子节点中存在比根更大的元素
                    biggerIndex = array[leftChildIndex]<array[rightChildIndex] ? rightChildIndex :leftChildIndex;
                }
    
            }else if(leftChildIndex<=lastIndex){  //只存在左子节点
    
                if(array[leftChildIndex]>array[rootIndex]){  //左子节点更大
                    biggerIndex = leftChildIndex;
                }
            }
    
            if(biggerIndex != rootIndex){  //找到了比根更大的子节点
    
                swap(rootIndex,biggerIndex);
    
                //交换位置后可能会破坏子树,将焦点转向交换了位置的子节点,调整以它为根的子树
                adjustHeap(biggerIndex,lastIndex);
            }
        }
    
        /**
         * 将数组按照完全二叉树的形式打印出来
         */
        private static void printTree(int len){
    
            int layers = (int)Math.floor(Math.log((double)len)/Math.log((double)2))+1;  //树的层数
            int maxWidth = (int)Math.pow(2,layers)-1;  //树的最大宽度
            int endSpacing = maxWidth;
            int spacing;
            int numberOfThisLayer;
            for(int i=1;i<=layers;i++){  //从第一层开始,逐层打印
                endSpacing = endSpacing/2;  //每层打印之前需要打印的空格数
                spacing = 2*endSpacing+1;  //元素之间应该打印的空格数
                numberOfThisLayer = (int)Math.pow(2, i-1);  //该层要打印的元素总数
    
                int j;
                for(j=0;j<endSpacing;j++){
                    System.out.print("  ");
                }
    
                int beginIndex = (int)Math.pow(2,i-1)-1;  //该层第一个元素对应的数组下标
                for(j=1;j<=numberOfThisLayer;j++){
                    System.out.print(array[beginIndex++]+"");
                    for(int k=0;k<spacing;k++){  //打印元素之间的空格
                        System.out.print("  ");
                    }
                    if(beginIndex == len){  //已打印到最后一个元素
                        break;
                    }
                }
    
                System.out.println();
            }
            System.out.println();
        }
    
        private static void swap(int low,int high){
            int temp = array[high];
            array[high] = array[low];
            array[low] = temp;
        }
    }
    View Code
    [7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2, 10, -3]
    建堆:
                  10                              
          8              9              
      6      1      7      3      
    2  5  0  -1  -2  4  -3  
    
    调整堆:
                  9                              
          8              7              
      6      1      4      3      
    2  5  0  -1  -2  -3  
    
    调整堆:
                  8                              
          6              7              
      5      1      4      3      
    2  -3  0  -1  -2  
    
    调整堆:
                  7                              
          6              4              
      5      1      -2      3      
    2  -3  0  -1  
    
    调整堆:
                  6                              
          5              4              
      2      1      -2      3      
    -1  -3  0  
    
    调整堆:
                  5                              
          2              4              
      0      1      -2      3      
    -1  -3  
    
    调整堆:
                  4                              
          2              3              
      0      1      -2      -3      
    -1  
    
    调整堆:
          3              
      2      -1      
    0  1  -2  -3  
    
    调整堆:
          2              
      1      -1      
    0  -3  -2  
    
    调整堆:
          1              
      0      -1      
    -2  -3  
    
    调整堆:
          0              
      -2      -1      
    -3  
    
    调整堆:
      -1      
    -2  -3  
    
    调整堆:
      -2      
    -3  
    
    [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    View Code

    堆排序的特性:

    一个长度为n的数组,可以看成是一个array[0,......,n-1]的完全二叉树。

    子节点索引为n-1的二叉树,其父节点的索引为(n-2)/2。

    父节点索引为i的二叉树,其子节点的索引分别为2*i+1和2*i+2。

    模板:

    import java.util.Arrays;
    
    public class Main {
        static  int[] array = {7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2,10,-3};
        public static void main(String[] args) throws InterruptedException {
            System.out.println(Arrays.toString(array));
            heapSort(array);
            System.out.println(Arrays.toString(array));
        }
        
        //堆排序
        public static int[] heapSort(int[] array){
            array = buildMaxHeap(array); //初始建堆,array[0]为第一趟值最大的元素
            for(int i=array.length-1;i>1;i--){
                int temp = array[0];  //将堆顶元素和堆低元素交换,即得到当前最大元素正确的排序位置
                array[0] = array[i];
                array[i] = temp;
                adjustDownToUp(array, 0,i);  //整理,将剩余的元素整理成堆
            }
            return array;
        }
    
        //构建大根堆:将array看成完全二叉树的顺序存储结构
        private static  int[] buildMaxHeap(int[] array){
            //从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆
            for(int i=(array.length-2)/2;i>=0;i--){
                adjustDownToUp(array, i,array.length);
            }
            return array;
        }
    
        //将元素array[k]自下往上逐步调整树形结构
        private static void adjustDownToUp(int[] array,int k,int length){
            int temp = array[k];
            for(int i=2*k+1; i<length-1; i=2*i+1){    //i为初始化为节点k的左孩子,沿节点较大的子节点向下调整(即选择节点i中较大的子节点的左孩子为新的i,有点绕)
                if(i<length && array[i]<array[i+1]){  //取节点较大的子节点的下标
                    i++;   //如果节点的右孩子>左孩子,则取右孩子节点的下标
                }
                if(temp>=array[i]){  //根节点 >=左右子女中关键字较大者,调整结束
                    break;
                }else{   //根节点 <左右子女中关键字较大者
                    array[k] = array[i];  //将左右子结点中较大值array[i]调整到双亲节点上
                    k = i; //【关键】修改k值,以便继续向下调整
                }
            }
            array[k] = temp;  //被调整的结点的值放人最终位置
        }
    }
    [7, 8, 9, 6, 1, 4, 3, 2, 5, 0, -1, -2, 10, -3]
    [-2, -3, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    View Code

    看堆时,发现最大的k个数,肯定在堆的前k排,比如第二大的数,肯定在第二排,不是根节点的左孩子,就是根节点的右孩子,按这种方式,可以发现堆排序有很大的优化空间。

    http://blog.csdn.net/u012152619/article/details/47306053

    http://blog.csdn.net/u012152619/article/details/47452813

    http://www.cnblogs.com/CherishFX/p/4643940.html

  • 相关阅读:
    修复 Visual Studio Error “No exports were found that match the constraint”
    RabbitMQ Config
    Entity Framework Extended Library
    Navisworks API 简单二次开发 (自定义工具条)
    NavisWorks Api 简单使用与Gantt
    SQL SERVER 竖表变成横表
    SQL SERVER 多数据导入
    Devexpress GridControl.Export
    mongo DB for C#
    Devexress XPO xpPageSelector 使用
  • 原文地址:https://www.cnblogs.com/hongdada/p/6171377.html
Copyright © 2020-2023  润新知