zoukankan      html  css  js  c++  java
  • 排序算法

    1.冒泡排序

    1. 比较相邻的两个元素。如果第一个比第二个大,就交换他们两个。
    2. 后移一位,对后面每一对相邻元素作同样的比较,一直比较到队列的最右端,此时最大值已经位于最右端了。
    3. 重新回归到最左端开始第二趟排序,再次从左到右两两比较。当碰到上次排定的元素后(已经排定的值无需再参与后面的排序了),就返回到最左端开始下一趟排序。
    4. 不断执行这个过程,直到所有值都排定。
    时间复杂度:O(n*n)
       /**
         * 冒泡排序
         * @param arr
         */
        public void bubbleSort(int[] arr){
            for (int out = arr.length-1; out >1 ; out--) {
                for (int in = 0; in < out; in++) {
                    if(arr[in] > arr[in+1]){
                        swap(arr, in, in+1);
                    }
                }
            }
        }
        private void swap(int[] arr, int aIndex, int bIndex){
            int temp = arr[aIndex];
            arr[aIndex] = arr[bIndex];
            arr[bIndex] = temp;
        }

    2.选择排序

    1. 设定一个标志位(从位置0开始)。
    2. 从标志位开始线性向后遍历列表,找出最小值,与标志位所在位置的数值交换。
    3. 标志位后移一位。继续第2步的操作。直到标志位到达队列的最后一位,此时已完成排序。

    时间复杂度:O(n*n)

    特点:改进了冒泡排序,将交换次数从O(n*n)减少到O(n),但是比较次数仍为O(n*n)

     /**
         * 选择排序
         * @param arr
         */
        public void selectSort(int[] arr){
            int minIndex;
            for (int out = 0; out < arr.length -1; out++) {
                minIndex = out;
                for (int in = out+1; in < arr.length; in++) {
                    if(arr[minIndex] > arr[in]){
                        minIndex = in;
                    }
                }
                swap(arr, out, minIndex);
            }
        }
    
        private void swap(int[] arr, int aIndex, int bIndex){
            int temp = arr[aIndex];
            arr[aIndex] = arr[bIndex];
            arr[bIndex] = temp;
        }

    3.插入排序

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

    时间复杂度:O(n*n)

    特点:虽然时间复杂度仍为O(n*n),但是一般情况下,要比冒泡排序快一倍,比选择排序还要快点。如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。

      /**
         * 插入排序
         * @param arr
         */
        public void insertSort(int[] arr, int left, int right){
            int in;
            int markedNum;
            for (int out = left+1; out <= right; out++) {
                in = out;
                markedNum = arr[out];
                while(in > left && arr[in] >= markedNum){
                    arr[in]= arr[in-1];
                    in--;
                }
                arr[in] = markedNum;
            }
        }
    

    4.归并排序

    1. 假设序列共有n个元素。
    2. 将序列每相邻两个数字进行归并操作(merge),形成floor(n/2)个序列,排序后每个序列包含两个元素
    3. 将上述序列再次进行相邻两个的归并,形成floor(n/4)个序列,每个序列包含四个元素
    4. 重复步骤2,直到所有的序列都归并成一个,即完成了排序。

    时间复杂度:O(n log n

     /**
         * 归并排序
         * @param arr
         */
        public void mergeSort(int[] arr, int low, int high){
            if(low == high) {
                return;
            }else{
                int mid = (low + high)/2;
                mergeSort(arr,low,mid);
                mergeSort(arr,mid+1,high);
                merge(arr,high,mid,low);
            }
        }
    
        private void merge(int[] arr, int high, int mid, int low){
            int arrLen = arr.length;
            int[] newArr = new int[arrLen];
            int lowFlag= low;
            int highFlag = mid+1;
            int i = 0;
            int totalNum = high - low +1;
            while (lowFlag <= mid && highFlag <= high){
                if(arr[lowFlag] < arr[highFlag]){
                    newArr[i++] = arr[lowFlag];
                    lowFlag++;
                }else{
                    newArr[i++] = arr[highFlag];
                    highFlag++;
                }
            }
    
            while(lowFlag <= mid){
                newArr[i++] = newArr[lowFlag++];
            }
    
            while(highFlag <= high){
                newArr[i++] = newArr[highFlag++];
            }
    
            for (int j = 0; j <totalNum; j++) {
                arr[j+low] = newArr[j];
            }
        }

    4.希尔排序

    1. 设置增量为h
    2. 将间隔为h的元素进行插入排序,从而使数据能够大跨度的移动。
    3. 完成一趟排序后,减小数据间的间隔n再进行排序。一般为(h = (h-1)/3)
    4. 重复步骤2,直到完成间隔为1的排序,算法结束。

    时间复杂度:大约为mathcal{O}( nlog^2 n )

    特点:希尔排序是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时数据每一趟排序需要的个数很少,但数据项的距离很长。当n值减小时每一趟需要和动的数据增多,此时已经接近于它们排序后的最终位置。

    /**
         * 希尔排序
         * @param arr
         */
        public void shellSort(int[] arr){
            int h = 1;
            int arrLen = arr.length;
            int temp;
            int in;
            while(h < arrLen/3){
                h = h * 3 + 1;
            }
    
            while(h > 0){
                for (int i = h; i < arrLen; i++) {
                    temp = arr[h];
                    in = i;
                    while(in>h-1 && arr[in-h] >= temp){
                        arr[in] = arr[in - h];
                        in -=h;
                    }
                    arr[in] = temp;
                }
                h = (h-1)/3;
            }
        }
    

    5.快速排序

    1. 找出一个元素(理论上可以随便找一个)作为基准(pivot)。
    2. 对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。
    3. 递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正确位置,排序完成

    时间复杂度:O(N*logN)

     /**
         * 快速排序
         * @param arr
         * @param left
         * @param right
         */
        public void quickSort(int[] arr, int left, int right){
            int size = right - left + 1;
            if(size < 10){
                insertSort(arr, left, right);
            }else{
                if(left >= right){
                    return;
                }else{
                    int mid = midOf3(arr, left, right);
                    int partition = partitionIt(arr, left, right, mid);
                    quickSort(arr, left, partition-1);
                    quickSort(arr, partition + 1, right);
                }
            }
    
        }
    
        private int midOf3(int[] arr, int left, int right){
            int mid = (left + right)/2;
            if(arr[left] > arr[mid]){
                swap(arr, left, mid);
            }
            if(arr[left] > arr[right]){
                swap(arr, left, right);
            }
            if(arr[mid] > arr[right]) {
                swap(arr, mid, right);
            }
            swap(arr, mid, right-1);
            return arr[right -1];
        }
    
        private int partitionIt(int[] arr, int left, int right, int pivot){
            int rightFlag = right;
            int leftFlag = left-1;
            while(true){
                while(rightFlag > 0 && arr[rightFlag --] > pivot);
                while(arr[leftFlag ++ ] < pivot);
                if(leftFlag >= rightFlag) {
                    break;
                }else{
                    swap(arr, leftFlag, rightFlag);
                }
            }
            swap(arr, leftFlag, right);
            return leftFlag;
        }
    

    6.堆排序

     1、堆(完全二叉树),用数组存储。

    • 大堆(根比节点大)
    • 小堆(根比节点小)
    • 堆排序(每次构建最大堆, 根节点是所有数中最大的值嘛。每次移走最大的后,再构建一次大堆,就能得到下一个最大值。);
    • 根节点索引值计算 n = (0  ~  (长度-1)/2), 左孩子 2*n +1  右孩子 2*n +2
    public class HeapSort {
        private static int[] sort = new int[]{1,0,10,20,3,5,6,4,9,8,12,17,34,11};
        public static void main(String[] args) {
            buildMaxHeapify(sort);
            heapSort(sort);
            print(sort);
        }
    
        private static void buildMaxHeapify(int[] data){
            //没有子节点的才需要创建最大堆,从最后一个的父节点开始
            int startIndex = getParentIndex(data.length - 1);
            //从尾端开始创建最大堆,每次都是正确的堆
            for (int i = startIndex; i >= 0; i--) {
                maxHeapify(data, data.length, i);
            }
        }
    
        /**
         * 创建最大堆
         * @param data
         * @param heapSize需要创建最大堆的大小,一般在sort的时候用到,因为最多值放在末尾,末尾就不再归入最大堆了
         * @param index当前需要创建最大堆的位置
         */
        private static void maxHeapify(int[] data, int heapSize, int index){
            // 当前点与左右子节点比较
            int left = getChildLeftIndex(index);
            int right = getChildRightIndex(index);
    
            int largest = index;
            if (left < heapSize && data[index] < data[left]) {
                largest = left;
            }
            if (right < heapSize && data[largest] < data[right]) {
                largest = right;
            }
            //得到最大值后可能需要交换,如果交换了,其子节点可能就不是最大堆了,需要重新调整
            if (largest != index) {
                int temp = data[index];
                data[index] = data[largest];
                data[largest] = temp;
                maxHeapify(data, heapSize, largest);
            }
        }
    
        /**
         * 排序,最大值放在末尾,data虽然是最大堆,在排序后就成了递增的
         * @param data
         */
        private static void heapSort(int[] data) {
            //末尾与头交换,交换后调整最大堆
            for (int i = data.length - 1; i > 0; i--) {
                int temp = data[0];
                data[0] = data[i];
                data[i] = temp;
                maxHeapify(data, i, 0);
            }
        }
    
        /**
         * 父节点位置
         * @param current
         * @return
         */
        private static int getParentIndex(int current){
            return (current - 1) >> 1;
        }
    
        /**
         * 左子节点position注意括号,加法优先级更高
         * @param current
         * @return
         */
        private static int getChildLeftIndex(int current){
            return (current << 1) + 1;
        }
    
        /**
         * 右子节点position
         * @param current
         * @return
         */
        private static int getChildRightIndex(int current){
            return (current << 1) + 2;
        }
    
        private static void print(int[] data){
            int pre = -2;
            for (int i = 0; i < data.length; i++) {
                if (pre < (int)getLog(i+1)) {
                    pre = (int)getLog(i+1);
                    System.out.println();
                }
                System.out.print(data[i] + " |");
            }
        }
    
        /**
         * 以2为底的对数
         * @param param
         * @return
         */
        private static double getLog(double param){
            return Math.log(param)/Math.log(2);
        }
    }
    

      

     
     
  • 相关阅读:
    【C&数据结构】---关于链表结构的前序插入和后序插入
    【LC_Overview1_5】---学会总结回顾
    【LC_Lesson5】---求最长的公共前缀
    xorm -sum 系列方法实例
    xorm -Alias,Asc,Desc方法实例
    xorm -Find方法实例
    xorm -Exist方法实例
    xorm -Get方法实例
    xorm-创建时间created
    xorm插入数据实例
  • 原文地址:https://www.cnblogs.com/happySmily/p/4734317.html
Copyright © 2011-2022 走看看