• 数据结构之排序


    这篇文章主要讨论常见的排序算法。

      排序算法分为内部排序和外部排序两种,内部排序是指只利用内存来完成的排序,外部排序是指借助外部存储设备完成的排序。外部排序主要针对记录比较多、内存无法一次全部加载的情况。我们这里主要关注内部排序。

      内部排序大致分为四类:1)插入排序;2)交换排序;3)选择排序;4)归并排序;5)基数排序。我们下面会分别进行描述。

      首先,我们来确定排序的对象,这里我们假设排序的对象是随机生成的非重复整数数组,有下面的辅助方法:

     
     1 public static int[] createArray(int count, int max)
     2 {
     3     if (count < 1) return null;
     4     int[] arrResult = new int[count];
     5     java.util.Random r = new java.util.Random();
     6     for(int i = 0; i < arrResult.length; i++)
     7     {
     8         int temp = 0;
     9         while(true)
    10         {
    11             temp = r.nextInt(max);
    12             int j = 0;
    13             for (j = 0; j < i; j++)
    14             {
    15                 if (arrResult[j] == temp) break;
    16             }
    17             if (j == i) break;
    18         }
    19         arrResult[i] = temp;
    20     }
    21     
    22     return arrResult;
    23 }
    24 
    25 private static void printArray(int[] array)
    26 {
    27     if (array == null)
    28     {
    29         return;
    30     }
    31     
    32     StringBuffer sb = new StringBuffer();
    33     for(int i = 0; i < array.length; i++)
    34     {
    35         sb.append(array[i]).append("->");
    36     }
    37     System.out.println(sb.substring(0, sb.length() - 2));
    38 }
     

      接下来,我们分别讨论上述几种排序算法。

      1) 插入排序。它的基本思想是将一个元素插入到一个已排序的序列中,构成一个更大的序列。直接插入排序和希尔排序(shell)都属于插入排序。

     
     1 public static void insertSort(int[] arrValue)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     printArray(arrValue);
     5     for (int i = 1; i < arrValue.length; i++)
     6     {
     7         int temp = arrValue[i];
     8         int j = i;
     9         for (j = i; j > 0; j--)
    10         {
    11             if (arrValue[j - 1] > temp)
    12             {
    13                 arrValue[j] = arrValue[j - 1];
    14             }
    15             else
    16             {
    17                 break;
    18             }
    19         }
    20         arrValue[j] = temp;
    21         printArray(arrValue);    
    22     }
    23 }
     

       运行结果

     
    22->32->2->46->9->29->20->45->3->26
    22->32->2->46->9->29->20->45->3->26
    2->22->32->46->9->29->20->45->3->26
    2->22->32->46->9->29->20->45->3->26
    2->9->22->32->46->29->20->45->3->26
    2->9->22->29->32->46->20->45->3->26
    2->9->20->22->29->32->46->45->3->26
    2->9->20->22->29->32->45->46->3->26
    2->3->9->20->22->29->32->45->46->26
    2->3->9->20->22->26->29->32->45->46
     
     
     1 public static void shellSort(int[] arrValue)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     int length = arrValue.length/2;
     5     printArray(arrValue);
     6     while(length >= 1)
     7     {
     8         shell(arrValue, length);
     9         length = length/2;
    10     }
    11 }
    12 
    13 private static void shell(int[] arrValue, int d)
    14 {
    15     for(int i = d; i < arrValue.length; i++)
    16     {
    17         if (arrValue[i] < arrValue[i -d])
    18         {
    19             int temp = arrValue[i];
    20             int j = i;
    21             while(j >= d)
    22             {
    23                 if (arrValue[j-d] > temp) 
    24                 {
    25                     arrValue[j] = arrValue[j - d];
    26                     j = j - d;
    27                 }
    28                 else
    29                 {
    30                     break;
    31                 }                
    32             }
    33             arrValue[j] = temp;
    34         }
    35         printArray(arrValue);
    36     }
    37 }
     

      运行结果

    14->21->1->26->6->40->5->46->9->25
    14->5->1->9->6->40->21->46->26->25
    1->5->6->9->14->25->21->40->26->46
    1->5->6->9->14->21->25->26->40->46

      2) 交换排序。它的基本思想是遍历待排序序列,不停交换元素,最终得到一个排序的序列。冒泡排序和快速排序都属于交换排序。

     
     1 public static void bubbleSort(int[] arrValue)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     printArray(arrValue);
     5     for(int i = 0; i < arrValue.length; i++)
     6     {
     7         for(int j = i+ 1; j < arrValue.length; j++)
     8         {
     9             if (arrValue[i] > arrValue[j])
    10             {
    11                 int temp = arrValue[i];
    12                 arrValue[i] = arrValue[j];
    13                 arrValue[j] = temp;
    14             }
    15         }
    16         printArray(arrValue);
    17     }
    18 }
     

       运行结果

     
    35->2->19->37->43->47->39->34->21->0
    0->35->19->37->43->47->39->34->21->2
    0->2->35->37->43->47->39->34->21->19
    0->2->19->37->43->47->39->35->34->21
    0->2->19->21->43->47->39->37->35->34
    0->2->19->21->34->47->43->39->37->35
    0->2->19->21->34->35->47->43->39->37
    0->2->19->21->34->35->37->47->43->39
    0->2->19->21->34->35->37->39->47->43
    0->2->19->21->34->35->37->39->43->47
    0->2->19->21->34->35->37->39->43->47
     
     
     1 public static void quickSort(int[] arrValue, int left, int right)
     2 {
     3     if(left < right)
     4     {
     5         int i = division(arrValue, left, right);
     6         quickSort(arrValue, left, i - 1);
     7         quickSort(arrValue, i + 1, right);
     8     }
     9 }
    10 
    11 private static int division(int[] arrValue, int left, int right)
    12 {
    13     int baseValue = arrValue[left];
    14     int midPos = left;
    15     printArray(arrValue);
    16     for (int i = left + 1; i <= right; i++)
    17     {
    18         if(arrValue[i] < baseValue) midPos++;
    19     }
    20     
    21     if (midPos == left)
    22     {
    23         return midPos;
    24     }
    25     
    26     arrValue[left] = arrValue[midPos]; 
    27     arrValue[midPos] = baseValue;
    28     
    29     if (midPos == right)
    30     {
    31         return midPos;
    32     }
    33     for (int i = left; i < midPos; i++)
    34     {
    35         if (arrValue[i] > baseValue)
    36         {
    37             for (int j = right; j > midPos; j--)
    38             {
    39                 if (arrValue[j] < baseValue)
    40                 {
    41                     int temp = arrValue[i];
    42                     arrValue[i] = arrValue[j];
    43                     arrValue[j] = temp;
    44                     right--;
    45                     break;
    46                 }
    47             }
    48         }
    49     }
    50             
    51     return midPos;
    52 }
     

      运行结果

     
    14->5->36->17->34->2->47->7->22->42
    7->5->2->14->34->36->47->17->22->42
    2->5->7->14->34->36->47->17->22->42
    2->5->7->14->34->36->47->17->22->42
    2->5->7->14->22->17->34->36->47->42
    2->5->7->14->17->22->34->36->47->42
    2->5->7->14->17->22->34->36->47->42
     

      3)选择排序。它的基本思想是每次都从子序列中取得最小或者最大的元素。简单选择排序和堆排序都属于选择排序。

     
     1 public static void selectSort(int[] arrValue)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     printArray(arrValue);
     5     for (int i = 0; i < arrValue.length; i++)
     6     {
     7         int minValue = arrValue[i];
     8         int minIndex = i;
     9         for (int j = i; j < arrValue.length; j++)
    10         {
    11             if (arrValue[j] < minValue) 
    12             {
    13                 minIndex = j;
    14                 minValue = arrValue[j]; 
    15             }
    16         }
    17         if (i != minIndex)
    18         {
    19             int temp = arrValue[i];
    20             arrValue[i] = arrValue[minIndex];
    21             arrValue[minIndex] = temp;
    22         }
    23         printArray(arrValue);
    24     }
    25 }
     

       运行结果

     
    43->28->29->31->37->32->27->36->12->3
    3->28->29->31->37->32->27->36->12->43
    3->12->29->31->37->32->27->36->28->43
    3->12->27->31->37->32->29->36->28->43
    3->12->27->28->37->32->29->36->31->43
    3->12->27->28->29->32->37->36->31->43
    3->12->27->28->29->31->37->36->32->43
    3->12->27->28->29->31->32->36->37->43
    3->12->27->28->29->31->32->36->37->43
    3->12->27->28->29->31->32->36->37->43
    3->12->27->28->29->31->32->36->37->43
     
     
     1 public static void heapSort(int[] arrValue)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     printArray(arrValue);
     5     for (int i = arrValue.length/2 - 1; i>=0; i--)
     6     {
     7         heapAdjust(arrValue, i, arrValue.length);
     8     }
     9     printArray(arrValue);
    10     for (int i = arrValue.length - 1; i > 0; i--)
    11     {
    12         int temp = arrValue[0];
    13         arrValue[0] = arrValue[i];
    14         arrValue[i] = temp;
    15                     
    16         heapAdjust(arrValue, 0, i);
    17         printArray(arrValue);
    18     }
    19     
    20 }
    21 
    22 private static void heapAdjust(int[] arrValue, int parent, int length)
    23 {
    24     int child = 2* parent + 1;
    25     int temp = arrValue[parent];
    26     while(child < length)
    27     {
    28         if (child + 1 < length && arrValue[child] < arrValue[child + 1])
    29         {
    30             child = child + 1;
    31         }
    32         if (temp > arrValue[child])
    33         {
    34             break;
    35         }
    36         arrValue[parent] = arrValue[child];
    37         
    38         parent = child;
    39         child = parent * 2 + 1;
    40         
    41     }
    42     arrValue[parent] = temp;
    43 }
     

      运行结果

     
    4->26->29->7->30->2->19->42->13->46
    46->42->29->13->30->2->19->7->4->26
    42->30->29->13->26->2->19->7->4->46
    30->26->29->13->4->2->19->7->42->46
    29->26->19->13->4->2->7->30->42->46
    26->13->19->7->4->2->29->30->42->46
    19->13->2->7->4->26->29->30->42->46
    13->7->2->4->19->26->29->30->42->46
    7->4->2->13->19->26->29->30->42->46
    4->2->7->13->19->26->29->30->42->46
    2->4->7->13->19->26->29->30->42->46
     

       4)归并排序。它的基本思想是递归和分治。

     
     1 public static void mergeSort(int[] arrValue, int start, int end)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     if (start + 1 < end)
     5     {
     6         int mid = (start + end)/2;
     7         mergeSort(arrValue, start, mid);
     8         mergeSort(arrValue, mid, end);
     9         merge(arrValue, start, mid, end);
    10         printArray(arrValue);
    11     }
    12 
    13 }
    14 
    15 private static void merge(int[] arrValue, int start, int mid, int end)
    16 {
    17     int[] temp = new int[end - start];
    18     
    19     int index1 = start;
    20     int index2 = mid;
    21     int index = 0;
    22     while(index1 < mid && index2 < end)
    23     {
    24         if (arrValue[index1] < arrValue[index2])
    25         {
    26             temp[index] = arrValue[index1];
    27             index1++;
    28         }
    29         else
    30         {
    31             temp[index] = arrValue[index2];
    32             index2++;
    33         }
    34         index++;
    35     }
    36     
    37     if (index1 < mid)
    38     {
    39         while(index1 < mid)
    40         {
    41             temp[index] = arrValue[index1];
    42             index1++;
    43             index++;
    44         }
    45     }
    46     
    47     if (index2 < end)
    48     {
    49         while(index2 < mid)
    50         {
    51             temp[index] = arrValue[index2];
    52             index2++;
    53             index++;
    54         }
    55     }
    56     
    57     for (int i = 0; i < index; i++)
    58     {
    59         arrValue[start + i] = temp[i];
    60     }
    61 }
     

      运行结果

     
    41->49->9->31->23->0->25->2->6->7
    41->49->9->23->31->0->25->2->6->7
    41->49->9->23->31->0->25->2->6->7
    9->23->31->41->49->0->25->2->6->7
    9->23->31->41->49->0->25->2->6->7
    9->23->31->41->49->0->25->2->6->7
    9->23->31->41->49->0->25->2->6->7
    9->23->31->41->49->0->2->6->7->25
    0->2->6->7->9->23->25->31->41->49
     

       5)基数排序。基数排序的思想和桶排序类似,它首先按照个位数值将序列放入到0-9共10个桶中,然后依次输出,接着,对新的序列按照十位数值再次放入桶中,然后再输出,以此类推,直到所有树的位数都遍历完毕,就可以得到排好序的序列。

     
     1 public static void radixSort(int[] arrValue)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     
     5     HashMap<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
     6     int base = 10;
     7     printArray(arrValue);
     8     while(isNeedContinue(arrValue, base))
     9     {
    10         map.clear();
    11         for (int i = 0; i < arrValue.length; i++)
    12         {
    13             int key = arrValue[i]%base/(base/10);
    14             if (!map.containsKey(key))
    15             {
    16                 map.put(key, new ArrayList<Integer>());
    17             }
    18             map.get(key).add(arrValue[i]);
    19         }
    20         for (int i = 0, j = 0; i < 10; i++)
    21         {
    22             if (map.containsKey(i))
    23             {
    24                 for(Integer value : map.get(i))
    25                 {
    26                     arrValue[j] = value;
    27                     j++;
    28                 }
    29             }
    30         }
    31         base = base*10;
    32         printArray(arrValue);
    33     }
    34 }
    35 
    36 private static boolean isNeedContinue(int[] arrValue, int base)
    37 {
    38     for(int i = 0; i < arrValue.length; i++)
    39     {
    40         if (base/10 <= arrValue[i]) return true;
    41     }
    42     return false;
    43 }
     

      运行结果

    38->16->48->27->45->44->3->22->14->42
    22->42->3->44->14->45->16->27->38->48
    3->14->16->22->27->38->42->44->45->48

      6)其他排序   也有一些其他排序算法比较巧妙,例如计数排序,它对于不重复序列排序来说,有时是一个很好的选择,它会首先计算序列的最小值和最大值,创建一个flag数组,数组长度为最大值和最小值之差,然后遍历序列,更新flag数组,最后遍历flag数组,输出排序结果。

     
     1 public static void smartSort(int[] arrValue)
     2 {
     3     if (arrValue == null || arrValue.length < 2) return;
     4     int min = arrValue[0];
     5     int max = arrValue[0];
     6     printArray(arrValue);
     7     for (int i = 1; i < arrValue.length; i++)
     8     {
     9         if (arrValue[i] < min) min = arrValue[i];
    10         if (arrValue[i] > max) max = arrValue[i];
    11     }
    12     int[] arrFlag = new int[max - min + 1];
    13     for (int i = 0; i < arrFlag.length; i++) arrFlag[i] = 0;
    14     printArray(arrFlag);
    15     for (int i = 0; i < arrValue.length; i++)
    16     {
    17         arrFlag[arrValue[i] - min] = 1;
    18     }
    19     printArray(arrFlag);
    20     for(int i = 0, j = 0; i < arrFlag.length; i++)
    21     {
    22         if (arrFlag[i] == 1)
    23         {
    24             arrValue[j] = i + min;
    25             j++;
    26         }
    27     }
    28     printArray(arrValue);
    29 }
     

       运行结果

    2->32->35->0->38->26->21->10->22->5
    0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0->0
    1->0->1->0->0->1->0->0->0->0->1->0->0->0->0->0->0->0->0->0->0->1->1->0->0->0->1->0->0->0->0->0->1->0->0->1->0->0->1
    0->2->5->10->21->22->26->32->35->38

      下面我们来总结分析上述各排序算法

    排序算法 平均时间复杂度 最优时间复杂度 最坏时间复杂度 空间复杂度 稳定性
    直接插入排序 O(n*n) O(n) O(n*n) O(1) 稳定
    希尔(shell)排序       O(1) 不稳定
    冒泡排序 O(n*n) O(n) O(n*n) O(1) 稳定
    快速排序 O(n*logn) O(n*logn) O(n*logn) O(n*logn) 不稳定
    简单选择排序 O(n*n) O(n) O(n*n) O(1) 不稳定
    堆排序 O(n*logn) O(n*logn) O(n*logn) O(1) 不稳定
    归并排序 O(n*logn) O(n*logn) O(n*logn) O(n) 稳定
    基数排序 O(d(n+radix)) O(d(n+radix)) O(d(n+radix)) O(radix) 稳定
  • 相关阅读:
    odoo12 物流 自动计算运费 ,采购销售使用不同计量单位自动换算
    ERP不规范,同事两行泪
    47.Odoo产品分析 (五) – 定制板块(2) – 为业务自定义odoo(2)
    48.Odoo产品分析 (五) – 定制板块(3) – 修改文件和报告(1)
    46.Odoo产品分析 (五) – 定制板块(2) – 为业务自定义odoo(1)
    44.Odoo产品分析 (五) – 定制板块(1) – 管理odoo安装(1)
    pytorch的HingeEmbeddingLoss 有先后顺序
    安装pytorch_geometric
    安装visual studio2019
    笔记本配置win10+cuda 10 + pytorch
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/3444602.html
Copyright © 2020-2023  润新知