zoukankan      html  css  js  c++  java
  • 选择排序

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

    简单选择排序:

    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

  • 相关阅读:
    Java设计模式—状态模式
    Java设计模式—备忘录模式
    android AsyncTask介绍
    Android UI线程和非UI线程
    Java设计模式—代理模式
    Java设计模式—命令模式
    <Android 应用 之路> MPAndroidChart~PieChart
    FPGA的EPCS 配置的2种方法 FPGA下载程序的方法(EPCS)
    如何将.sof转换成.jic
    quartus ii工程文件的分析
  • 原文地址:https://www.cnblogs.com/hongdada/p/6171377.html
Copyright © 2011-2022 走看看