zoukankan      html  css  js  c++  java
  • 排序算法_10种经典排序整合

    基础回顾:

    【1】冒泡排序:从头开始,两两相近比较,小的往前冒泡

    【2】选择排序:从头开始,每一轮选出最小的放到最前面

    【3】插入排序:默认头部是排好序的,每次从头部下一个往前冒泡插入

    组合:前提条件——几乎已经排好序的数据等等

    希尔排序是基于插入排序的以下两点性质而提出改进方法的:

    • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
    • 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

    【1】希尔排序:通过增量分段使用插入排序,有一限制:最终的分段增量一定为1——这也增加其复杂度!

    public static  void ShellSort(int[] data){
            int g = 1; //保障最终增量为1
             while(g<data.length){
                g = g*3+1;//生产增量
             }
             while(g>0){
                 for(int i = g;i<data.length;i++){
                     int j = i - g;
                     int temp = data[i];//下面就是插入排序
                     while(j>=0 && data[j]>temp){
                         data[j+g] = data[j];
                         j -= g;
                     }

                     data[j+g] = temp;
                 }
                 g = g/3;
             }
             System.out.println(Arrays.toString(data));
         }

    归并排序——分治法【递归】

    创建在归并操作上的一种有效的排序算法,效率为O(n log n)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。

    对递归的真正认知:明白递归停地时候,关键节点的操作!——对于分治两两进行拼接排序——递归到底:两两数字,然后两两组合的归并

    public static void sort(int[] data,int left,int right,int[] temp){
             if (left<right) {
                 int mid = (left + right)/2;
                 sort(data, left, mid, temp);
                 sort(data, mid+1, right, temp);
                 //对于分治两两进行拼接排序——递归到底:两两数字,然后两两组合的归并
                 merge(data, left, mid, right, temp);
             }
         }
         public static void merge(int[] data,int left,int mid ,int right,int[] temp){
             int i = left;
             int j = mid+1;
             int t = 0;
            
             while(i<=mid && j<=right){
                 if (data[i]<data[j]) {
                     temp[t++] = data[i++];
                 }else {
                     temp[t++] = data[j++];
                 }
             }
             while(i<=mid){
                 temp[t++] = data[i++];
             }
             while(j<=right){
                 temp[t++] = data[j++];
             }
             t=0;
             while (left<=right) {
                 data[left++] = temp[t++];
             }
         }

    ============================================

    改进1:采用两个线程:???

    【1】线程之间共享数据data,一个负责拆分,一个负责合并




    快速排序:分治+冒泡

    核心思想:

             -先对左右两端以及中心的三个元素排序,将中值作为基准值;

             -将基准值放到倒数第二位,开始将基准值之前的数据中大于基准值的放到靠近基准值一侧,然后将基准值与其左侧大于其值的第一个交换,将整个数据划分为左右两个区域

             -继续分别对左右两个区域进行递归分治——结素标志:两个数值冒泡交换位置

             -

    public static void sort(int[] data,int left,int right){
             if (left<right) {
                 dealPivot(data, left, right);
                 int mid = (left+right)/2;
                 swap(data,mid ,right-1);
                 int i = left;
                 int j = right-1;
                 while (true) {
                     while (data[++i]<data[right-1]) {}
                     while(j>i && data[--j]>data[right-1]){}
                     swap(data, i, j);
                     if (i>=j) {
                         break;
                     }
                 }
                 swap(data, i, right-1);
                 sort(data, left, i-1);
                 sort(data, i+1, right);
             }
         }
         public static void dealPivot(int[] data,int left,int right){
             int mid = (left+right)/2;
             if (data[left] > data[mid]) {
                 swap(data, left, mid);
             }
             if (data[left] > data[right]) {
                 swap(data, left, right);
             }
             if (data[mid] > data[right]) {
                 swap(data, mid, right);
             }
         }
         public static void swap(int[] data,int left,int right){
             int temp = data[left];
             data[left] = data[right];
             data[right] = temp;
         }

    堆排序——堆结构、完全二叉树:交换堆顶与堆尾;缩小堆的尺寸

    【1】大顶堆:

         -is[i] >= is[2i+1]

         -is[i] >= is[2i+2]

    【2】小顶堆

         -is[i] <= is[2i+1]

         -is[i] <= is[2i+2]

    ===========================

    【1】找第一个非叶子节点: data.length/2 - 1

    =====逻辑思路到代码的转换又是一个过程!!!


    public static void sort(int[] data){

    //先进行一次全部非叶子节点的大顶堆调整——由下至上,由右往左
             for(int i=data.length/2-1;i>=0;i--){
                 injust(data, i, data.length);
             }

    //整体交换一次堆顶最大元素放置末尾,做一次大顶堆调整——由上至下,由左往右       
             for(int i=data.length-1;i>0;i--){
                 swap(data, 0, i);
                 injust(data, 0, i);
             }
         }
        
         public static void injust(int[]data,int i,int length){
             int temp = data[i];
             //解决该小堆排序问题,以及由于堆顶调整导致下面节点的重新调整
             for(int k=i*2+1;k<length;k=k*2+1){
                 if (k<length-1 && data[k]<data[k+1]) {
                     k++;
                 }
                 if (data[k]>temp) {
                     data[i] = data[k];
                     i = k;
                 }else {
                     break;//说明后续节点没有受到影响,结束
                 }
             }
             data[i] = temp;
            
         }
        
         public static void swap(int[] data,int left,int right){
             int temp = data[left];
             data[left] = data[right];
             data[right] = temp;
         }
        

    ==============计数排序:有一定的前置条件:在特定条件下,比以上7种都要快

    【1】计数排序:固定范围正整数放入到额外开辟的空间【最好均匀分布满足一定的统计分布】

         -核心思想:通过一个区段计数器:游标=源数组数据,value:源数组数据出现频次

    public static void sort(int[] data){
             int max = data[0];
             for(int i=0;i<data.length;i++){
                 if (data[i]>max) {
                     max = data[i];
                 }
             }
             int[] temp = new int[max+1];
             for(int i=0;i<data.length;i++){
                 temp[data[i]]++;
             }
             int index = 0;
             for(int i=0;i<temp.length;i++){
                 for (int j = 0; j < temp[i]; j++) {
                     data[index++]=i;
                 }
             }
         }

    桶排序——hashMap  && 红黑树

    核心思想:通过自定义桶的个数,通过最大最小值划定跨度,采用likedList数据结构进行插入排序,最终合并所有数据。

    public static int[] sort(int[] data){
             int bucketCount = 3;
             int max=data[0];
             int min=data[0];
             for(int i:data){
                 if (max<i) {
                     max = i;
                 }
                 if (min>i) {
                     min = i;
                 }
             }
             double space = (max-min+1)/bucketCount;
             List<Integer>[] buckets = new LinkedList[bucketCount];
             for(int num:data){
                 int index = (int)(Math.floor((num-min)/space));
                 if (buckets[index]==null) {
                     buckets[index] = new LinkedList<Integer>();
                     buckets[index].add(num);
                 }else {
                     for(int i=buckets[index].size()-1;i>=0;i--){
                         if (num<buckets[index].get(i)) {
                             if (i+1>buckets[index].size()-1) {
                                 buckets[index].add(buckets[index].get(i));
                                 if (i==0) {
                                     buckets[index].set(i, num);
                                 }
                             }else {
                                 buckets[index].set(i+1, buckets[index].get(i));
                             }
                            
                         }else {
                             if (i+1>buckets[index].size()-1) {
                                 buckets[index].add(num);
                                 i++;
                                 break;
                             }else {
                                 buckets[index].set(i+1, num);
                                 break;
                             }
                         }
                     }
                 }
             }
             int index = 0;
             for(int i=0;i<=buckets.length-1;i++){
                 for(int j=0;j<=buckets[i].size()-1;j++){
                     data[index++] = buckets[i].get(j);
                 }
             }
             return data;
         }

    基数排序:对个、十、百、千…位依次进行排序

    基数排序(英语:Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机(Tabulation Machine)上的贡献。

    public static void sort(int[] data,int d){
             int n = 1;
             int length = data.length;
             //本质桶一维数组+链表
             while(n<d){
                 int[][] buckets = new int[10][data.length]; //桶:一维对应桶的位序,二维对应桶内个数,每一位值位存储的实际值
                 int[] order = new int[10];
                 for(int num:data){
                     int cp = num/n%10;
                     buckets[cp][order[cp]]=num;
                     order[cp]++;
                 }
                 int index = 0;
                 for(int i=0;i<order.length;i++){
                     for(int j=0;j<order[i];j++){
                         data[index++] = buckets[i][j];
                     }
                 }
                 n *= 10;
             }
         }

  • 相关阅读:
    2020916 spring总结
    20200915--事务
    20200915-mybatis基础
    20200911--使用注解开发
    20200910--Spring配置
    20200909--spring基础-IOC
    20200909-待补充
    20200909记我所看到的问题
    20200909-spring基础一
    面向对象
  • 原文地址:https://www.cnblogs.com/macro-renzhansheng/p/13461583.html
Copyright © 2011-2022 走看看