排序算法_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;
         }
     }

原文地址:https://www.cnblogs.com/macro-renzhansheng/p/13461583.html