zoukankan      html  css  js  c++  java
  • 排序算法【整理】

    一、分类

    二、时间复杂度

    • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
    • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
    • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
    • 空间复杂度:是指算法在计算机

    三、算法介绍及java实现(升序)

    注意:通过举例子考虑边界

    1、选择排序

     选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。

    选择排序是不稳定的排序方法,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了。

        public void xuanze(int[] nums){
            for(int i =0;i<nums.length-1;i++){ //最后一位默认有序
                int min = i;
                for(int j=i;j<nums.length;j++){
                  if(nums[min]>nums[j])
                    min=j;
                }
                int temp = nums[min];//交换排序
                nums[min] =nums[i];
                nums[i]=temp;
            }
        }

    2、冒泡排序

    每次比较相邻的元素,交换数组,大的值在前面。   时间复杂度由于交换操作多比选择排序高。

    稳定。

        public void maopao(int[] nums){
            for(int i =0;i<nums.length;i++){
                for(int j = 0;i<nums.length-i-1;i--){
                    if(nums[j]>nums[j+1]){
                        int temp = nums[j];
                        nums[j]=nums[j+1];
                        nums[j+1] = temp;
                    }}}
        }

    3、插入排序

    插入排序(Insertion sort)是一种简单直观且稳定的排序算法。如果有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,算法适用于少量数据的排序,时间复杂度O(n^2)。

    稳定

    public void charu(int[] nums){
            for(int i =1;i<nums.length;i++){
            //找到在已排序中的位置
            int pos=0;
            while(nums[pos]<nums[i]){
                pos++;
            }
            int temp = nums[i];
            for(int j= i;j>pos;j--){
                nums[j]=nums[j-1];
            }
            nums[pos] =temp;
            }}

    4、希尔排序

    第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序

    gap为增量,每次缩小二分之一的gap,在内部使用插入排序。不稳定。

    public void xier(int[] nums){
            int gap = nums.length;
            while(gap>0){
            gap/=2;
            for(int i =0;i<gap;i++){
                for(int j =i+gap;j<nums.length;j+=gap){//插入排序
                    int temp = nums[j];            
                    int k = j - gap;            
                    while (k >= 0 && nums[k] > temp) {                
                        nums[k + gap] = nums[k];                
                        k -= gap;            
                    }            
                    nums[k + gap] = temp;  
                }
            }
            if(gap==1)
            break;
            } }

    5、归并排序

    稳定。分治法思想,递归实现。

    java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。

     public static void guibing(int []arr){
            int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
            sort(arr,0,arr.length-1,temp);
        }
        private static void sort(int[] arr,int left,int right,int []temp){
            if(left<right){
                int mid = (left+right)/2;
                sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
                sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
                merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
            }
        }
        private static void merge(int[] arr,int left,int mid,int right,int[] temp){
            int i = left;//左序列指针
            int j = mid+1;//右序列指针
            int t = 0;//临时数组指针
            while (i<=mid && j<=right){
                if(arr[i]<=arr[j]){
                    temp[t++] = arr[i++];
                }else {
                    temp[t++] = arr[j++];
                }
            }
            while(i<=mid){//将左边剩余元素填充进temp中
                temp[t++] = arr[i++];
            }
            while(j<=right){//将右序列剩余元素填充进temp中
                temp[t++] = arr[j++];
            }
            t = 0;
            //将temp中的元素全部拷贝到原数组中
            while(left <= right){
                arr[left++] = temp[t++];
            }
        }

    6、堆排序

    不稳定。通过堆结构选择出最大值,后排序

    1.找到第一个非叶子节点 i = arr.length/2-1 , 开始遍历所有非叶子节点,调整堆大小,可得到一个最大堆

    2.从左至右判断子节点大小,选择出较大的一个,与父节点进行比较交换

    3.不断交换堆顶元素和末尾元素(已排序的末尾元素不考虑),排序完成。

        public static void dui(int []arr){
            //1.构建大顶堆
            for(int i=arr.length/2-1;i>=0;i--){
                //从第一个非叶子结点从下至上,从右至左调整结构
                adjustHeap(arr,i,arr.length);
            }
            //2.调整堆结构+交换堆顶元素与末尾元素
            for(int j=arr.length-1;j>0;j--){
                swap(arr,0,j);//将堆顶元素与末尾元素进行交换
                adjustHeap(arr,0,j);//重新对堆进行调整
            }
    
        }
    
        /**
         * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
         * @param arr
         * @param i
         * @param length
         */
        public static void adjustHeap(int []arr,int i,int length){
            int temp = arr[i];//先取出当前元素i
            for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
                if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
                    k++;
                }
                if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                    arr[i] = arr[k];
                    i = k;
                }else{
                    break;
                }
            }
            arr[i] = temp;//将temp值放到最终的位置
        }

    7、快速排序
    不稳定。 快速排序(Quicksort)是对冒泡排序的一种改进。

    1.以第一个值为基准值,从后往前找到小于基准值的值,复制至前方,开始从前往后找到大于基准值的值,复制至后方。

    2.当遍历完成后将基准值复制至最后位置

    3.递归基准值左右的数组

      public static void kuaipai(int[] arr, int leftIndex, int rightIndex) {
            if (leftIndex >= rightIndex) {
                return;
            }
            int left = leftIndex;
            int right = rightIndex;
            //待排序的第一个元素作为基准值
            int key = arr[left];
            //从左右两边交替扫描,直到left = right
            while (left < right) {
                while (right > left && arr[right] >= key) {
                    //从右往左扫描,找到第一个比基准值小的元素
                    right--;
                }
                //找到这种元素将arr[right]放入arr[left]中
                arr[left] = arr[right];
                while (left < right && arr[left] <= key) {
                    //从左往右扫描,找到第一个比基准值大的元素
                    left++;
                }
                //找到这种元素将arr[left]放入arr[right]中
                arr[right] = arr[left];
            }
            //基准值归位
            arr[left] = key;
            //对基准值左边的元素进行递归排序
            kuaipai(arr, leftIndex, left - 1);
            //对基准值右边的元素进行递归排序。
            kuaipai(arr, right + 1, rightIndex);
        }
     
  • 相关阅读:
    oracle中 connect by prior 递归算法
    sql优化__rownum的使用【转】
    ASP.NET Core四大部件
    .net core Socket
    .NET Core 配置文件
    .NET Core IOC AOP
    Quartz.Net—MisFire
    Quartz.Net—配置化
    Quartz.Net—IJob特性
    Quartz.Net—DateBuilder
  • 原文地址:https://www.cnblogs.com/huchengxi/p/12360783.html
Copyright © 2011-2022 走看看