• 十大排序算法汇总


    目录

    1、冒泡排序

    2、选择排序

    3、插入排序

    4、希尔排序

    5、归并排序

    6、快速排序

    7、堆排序

    8、计数排序

    9、桶排序

    10、基数排序


    1、冒泡排序

    思想:每次左右两两比较,把最大或最小元素放到最后,直到整体有序

    时间复杂度:O(n²)

    稳定性:稳定

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main7_1 {
    4. //冒泡排序
    5. //小到大排序
    6. public static void f8(int[] arr) {
    7. boolean flag=true;
    8. int mid;
    9. for (int i = arr.length-1; i > 0; i--) {
    10. for (int j = 0; j < i; j++) {
    11. if(arr[j]>arr[j+1]) {
    12. mid=arr[j];
    13. arr[j]=arr[j+1];
    14. arr[j+1]=mid;
    15. flag=false;
    16. }
    17. }
    18. //优化,提前整体有序
    19. if(flag) {
    20. return;
    21. }
    22. flag=true;
    23. }
    24. }
    25. //大到小排序
    26. public static void f9(int[] arr) {
    27. boolean flag=true;
    28. int mid;
    29. for (int i = arr.length-1; i > 0; i--) {
    30. for (int j = 0; j < i; j++) {
    31. if(arr[j]1]) {
    32. mid=arr[j];
    33. arr[j]=arr[j+1];
    34. arr[j+1]=mid;
    35. flag=false;
    36. }
    37. }
    38. //优化,提前整体有序
    39. if(flag) {
    40. return;
    41. }
    42. flag=true;
    43. }
    44. }
    45. public static void main(String[] args) {
    46. // TODO 自动生成的方法存根
    47. int[] arr= {5,2,8,9,2,6,7,10};
    48. // f8(arr);
    49. f9(arr);
    50. System.out.println(Arrays.toString(arr));
    51. }
    52. }

    2、选择排序

    思想:每次从待排数组中取一个最小或最大的元素放到前面,直到整体有序

    时间复杂度:O(n²)

    稳定性:不稳定

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main7_1 {
    4. //选择排序(简单选择排序)
    5. //小到大排序
    6. public static void f6(int[] arr) {
    7. int min=arr[0],p=0,mid;
    8. for (int i = 0; i < arr.length-1; i++) {
    9. for (int j = i+1; j < arr.length; j++) {
    10. if(arr[j]
    11. p=j;
    12. min=arr[j];
    13. }
    14. }
    15. mid=arr[p];
    16. arr[p]=arr[i];
    17. arr[i]=mid;
    18. min=arr[i+1];
    19. p=i+1;
    20. }
    21. }
    22. //大到小排序
    23. public static void f7(int[] arr) {
    24. int max=arr[0],p=0,mid;
    25. for (int i = 0; i < arr.length-1; i++) {
    26. for (int j = i+1; j < arr.length; j++) {
    27. if(arr[j]>max) {
    28. p=j;
    29. max=arr[j];
    30. }
    31. }
    32. mid=arr[p];
    33. arr[p]=arr[i];
    34. arr[i]=mid;
    35. max=arr[i+1];
    36. p=i+1;
    37. }
    38. }
    39. public static void main(String[] args) {
    40. // TODO 自动生成的方法存根
    41. int[] arr= {5,2,8,9,2,6,7,10};
    42. // f6(arr);
    43. f7(arr);
    44. System.out.println(Arrays.toString(arr));
    45. }
    46. }

    3、插入排序

    思想:每次取一个元素拆入到已排序的数组中有序的位置,直到整体有序

    时间复杂度:O(n²)

    稳定性:稳定

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main1 {
    4. //插入排序
    5. static void f8(int[] arr,int k) {//k代表个数或数组长度
    6. if(k==1)//k代表元素个数
    7. return;
    8. f8(arr,k-1);//先把前k-1个元素排好序
    9. int index=k-1;//index代表数组下标
    10. while(index>0&&arr[index]1]) {
    11. int mid=arr[index];
    12. arr[index]=arr[index-1];
    13. arr[index-1]=mid;
    14. index--;
    15. }
    16. }
    17. //方法二(前往后排序)
    18. static void f9(int[] arr,int index) {//index代表开始下标,为0
    19. if(index==arr.length)
    20. return;
    21. int r=index;
    22. while(r>0&&arr[r]1]) {
    23. int mid=arr[r];
    24. arr[r]=arr[r-1];
    25. arr[r-1]=mid;
    26. r--;
    27. }
    28. f9(arr,index+1);//把剩余的index+1下标元素排序
    29. }
    30. //方法三(后往前排序)
    31. static void f10(int[] arr,int index) {//index代表结束下标,为arr.length-1
    32. if(index==-1)
    33. return;
    34. int r=index;
    35. while(r1&&arr[r]>arr[r+1]) {
    36. int mid=arr[r];
    37. arr[r]=arr[r+1];
    38. arr[r+1]=mid;
    39. r++;
    40. }
    41. f10(arr,index-1);//把剩余的index-1下标元素排序
    42. }
    43. public static void main(String[] args) {
    44. // TODO 自动生成的方法存根
    45. int[] arr1=new int[]{2,5,99,5,1,-5,-9};
    46. f8(arr1,7);
    47. for (int i = 0; i < arr1.length; i++) {
    48. System.out.print(arr1[i]+",");
    49. }
    50. System.out.println();
    51. int[] arr2=new int[]{2,5,99,5,1,-5,-9};
    52. f9(arr2,0);
    53. for (int i = 0; i < arr2.length; i++) {
    54. System.out.print(arr2[i]+",");
    55. }
    56. System.out.println();
    57. int[] arr3=new int[]{2,5,99,5,1,-5,-9};
    58. f10(arr3,6);
    59. for (int i = 0; i < arr3.length; i++) {
    60. System.out.print(arr3[i]+",");
    61. }
    62. System.out.println();
    63. }
    64. }

    4、希尔排序

    思想:确定一个渐进缩小的增量,进行分组后在组内插入排序,直到整体有序(插入排序的进阶版)

    时间复杂度:O(nlogn)

    稳定性:不稳定

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main2 {
    4. //希尔排序(缩小增量排序,优化插入排序)
    5. static void f2(int arr[]) {
    6. for (int incre = arr.length/2; incre > 0; incre=incre/2) {
    7. for (int i = incre; i < arr.length; i++) {
    8. int target=i;
    9. while(target>=incre&&arr[target]
    10. int mid=arr[target];
    11. arr[target]=arr[target-incre];
    12. arr[target-incre]=mid;
    13. target-=incre;
    14. }
    15. }
    16. }
    17. }
    18. public static void main(String[] args) {
    19. // TODO 自动生成的方法存根=
    20. int arr1[]=new int[] {9,8,7,6,5,4,3,6,2,1,99,0,-4};
    21. f2(arr1);
    22. for (int i : arr1) {
    23. System.out.print(i+",");
    24. }
    25. System.out.println();
    26. }
    27. }

    5、归并排序

    思想:分治思想,把待排数组渐进分割,进行有序合并,直到整体有序(偏合并)

    时间复杂度:O(nlogn)

    稳定性:稳定

    1. package com.xch2.DiGui;
    2. public class Main5 {
    3. //归并排序
    4. static int[] arr1;
    5. static void f1(int[] arr,int l,int r) {
    6. arr1=new int[arr.length];//外移到递归函数外,不会多次new节省存储空间
    7. f2(arr,l,r);
    8. }
    9. static void f2(int[]arr,int l,int r) {
    10. if(l>=r)//递归出口
    11. return;
    12. int mid=l+((r-l)>>1),left=l,right=mid+1,ori=l;
    13. f2(arr,l,mid);//子递归
    14. f2(arr,mid+1,r);
    15. for (int i = 0; i < arr1.length; i++) {
    16. arr1[i]=arr[i];//更新辅助数组
    17. }
    18. while(left<=mid&&right<=r) {//递归体
    19. if(arr1[left]<=arr1[right]) {
    20. arr[ori]=arr1[left];
    21. left++;
    22. }else {
    23. arr[ori]=arr1[right];
    24. right++;
    25. }
    26. ori++;
    27. }
    28. while(left<=mid) {
    29. arr[ori]=arr1[left];
    30. left++;
    31. ori++;
    32. }
    33. }
    34. public static void main(String[] args) {
    35. // TODO 自动生成的方法存根
    36. int[] arr=new int[] {11,8,3,4,9,8,22,0,5,8,3};
    37. f1(arr,0,10);
    38. for (int i : arr) {
    39. System.out.print(i+" ");
    40. }
    41. System.out.println();
    42. }
    43. }

    6、快速排序

    思想:分治思想,先定主元把数组分为两(三)段[小于(等于)大于],后调整主元位置,递归渐进分割比较,直到整体有序(偏拆分)

    时间复杂度:O(nlogn)

    稳定性:不稳定

    其中,实现方法分为三种:

    1、双指针-单向扫描快速排序

    2、双指针-双向扫描快速排序

    3、三指针-双向扫描快速排序(相等元素优化)

    定主元的两种方法:

    1、取第一个

    2、三点中值法(推荐,取本段数组头中尾三个元素比较值)

    1. package com.xch2.DiGui;
    2. public class Main4 {
    3. //单向单指针扫描分区快排法
    4. static void f1(int[] arr,int l,int r) {
    5. if(l>=r)//递归出口
    6. return;
    7. int left=l+1,right=r,mid=0;
    8. while(left<=right) {//递归体
    9. if(arr[left]<=arr[l])
    10. left++;
    11. else {
    12. mid=arr[left];
    13. arr[left]=arr[right];
    14. arr[right]=mid;
    15. right--;
    16. }
    17. }
    18. mid=arr[right];
    19. arr[right]=arr[l];
    20. arr[l]=mid;
    21. f1(arr,l,right-1);//子递归
    22. f1(arr,right+1,r);
    23. }
    24. //双向双指针扫描分区快排法
    25. static void f2(int[] arr,int l,int r) {
    26. if(l>=r)//递归出口
    27. return;
    28. int left=l+1,right=r,mid=0;
    29. while(left<=right) {//递归体
    30. while(left<=right&&arr[left]<=arr[l])
    31. left++;
    32. while(left<=right&&arr[right]>arr[l])
    33. right--;
    34. if(left
    35. mid=arr[right];
    36. arr[right]=arr[left];
    37. arr[left]=mid;
    38. }
    39. }
    40. mid=arr[right];
    41. arr[right]=arr[l];
    42. arr[l]=mid;
    43. f2(arr,l,right-1);//子递归
    44. f2(arr,right+1,r);
    45. }
    46. //双向和等于三指针扫描分区快排法
    47. static void f3(int[] arr,int l,int r) {
    48. if(l>=r)//递归出口
    49. return;
    50. int equ=l,left=l+1,right=r,mid=0;
    51. while(left<=right) {//递归体
    52. while(left<=right&&arr[left]<=arr[l]) {
    53. if(arr[left]==arr[l]&&equ==l)
    54. equ=left;
    55. if(arr[left]
    56. mid=arr[left];
    57. arr[left]=arr[equ];
    58. arr[equ]=mid;
    59. equ++;
    60. }
    61. left++;
    62. }
    63. while(left<=right&&arr[right]>arr[l])
    64. right--;
    65. if(left
    66. mid=arr[right];
    67. arr[right]=arr[left];
    68. arr[left]=mid;
    69. }
    70. }
    71. if(equ!=l) {
    72. equ--;
    73. mid=arr[equ];
    74. arr[equ]=arr[l];
    75. arr[l]=mid;
    76. f3(arr,l,equ-1);//子递归
    77. f3(arr,right+1,r);
    78. }else {
    79. mid=arr[right];
    80. arr[right]=arr[l];
    81. arr[l]=mid;
    82. f3(arr,l,right-1);//子递归
    83. f3(arr,right+1,r);
    84. }
    85. }
    86. //以上方法均为去第一个随机数为比较主元
    87. //一般用三点取中值法取比较主元,如f4单指针,其他一样(取中值后和第一个数值换成为主元)
    88. //单向单指针扫描分区快排法(三点取中值为主元法)
    89. static void f4(int[] arr,int l,int r) {
    90. if(l>=r)//递归出口
    91. return;
    92. int left=l+1,right=r,mid=0;
    93. int midsub=l+((r-l)>>1);//三点取中值
    94. if(arr[l]>=arr[midsub]&&arr[midsub]>=arr[r]||
    95. arr[l]<=arr[midsub]&&arr[midsub]<=arr[r]) {
    96. mid=arr[midsub];
    97. arr[midsub]=arr[l];//换主元
    98. arr[l]=mid;
    99. }else if(arr[midsub]>=arr[r]&&arr[r]>=arr[l]||
    100. arr[midsub]<=arr[r]&&arr[r]<=arr[l]){
    101. mid=arr[r];
    102. arr[r]=arr[l];
    103. arr[l]=mid;
    104. }
    105. while(left<=right) {//递归体
    106. if(arr[left]<=arr[l])
    107. left++;
    108. else {
    109. mid=arr[left];
    110. arr[left]=arr[right];
    111. arr[right]=mid;
    112. right--;
    113. }
    114. }
    115. mid=arr[right];
    116. arr[right]=arr[l];
    117. arr[l]=mid;
    118. f4(arr,l,right-1);//子递归
    119. f4(arr,right+1,r);
    120. }
    121. public static void main(String[] args) {
    122. // TODO 自动生成的方法存根
    123. int[] arr=new int[] {0,1,9,5,4,1};
    124. // f1(arr,0,5);
    125. // f2(arr,0,5);
    126. // f3(arr,0,5);
    127. f4(arr,0,5);
    128. for (int i : arr) {
    129. System.out.print(i+" ");
    130. }
    131. System.out.println();
    132. }
    133. }

    7、堆排序

    思想:利用二叉树的特性,每次把最大或最小的元素比较到根节点维持一个大或小顶堆,取出根节点放到最后,直到整体有序

    时间复杂度:O(nlogn)

    稳定性:不稳定

    分为两种:

    1、小顶堆-逆向排序

    2、大顶堆-顺向排序

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main7 {
    4. //堆排序(小顶堆=逆序,大顶堆=顺序)
    5. //建小顶堆
    6. static void f1(int[] arr,int index,int leng) {//index初始为数组二分值减一
    7. if(index<0) //leng 初始为数组长度
    8. return;
    9. int left=2*index+1,right=2*index+2,mid;
    10. if(left==leng-1) {//最后一个父节点为单亲节点
    11. if(arr[left]
    12. mid=arr[left];
    13. arr[left]=arr[index];
    14. arr[index]=mid;
    15. }
    16. }else {
    17. if(arr[left]<=arr[right]&&arr[left]
    18. mid=arr[left];
    19. arr[left]=arr[index];
    20. arr[index]=mid;
    21. }else if(arr[right]<=arr[left]&&arr[right]
    22. mid=arr[right];
    23. arr[right]=arr[index];
    24. arr[index]=mid;
    25. }
    26. }
    27. f1(arr,index-1,leng);
    28. }
    29. //小顶堆转逆序数组
    30. static void f2(int arr[],int leng) {
    31. if(leng==1)
    32. return;
    33. f1(arr,leng/2-1,leng);
    34. int mid=arr[leng-1];
    35. arr[leng-1]=arr[0];
    36. arr[0]=mid;
    37. leng--;
    38. f2(arr,leng);
    39. }
    40. //建大顶堆
    41. static void f3(int[] arr,int index,int leng) {//index初始为数组二分值减一
    42. if(index<0) //leng 初始为数组长度
    43. return;
    44. int left=2*index+1,right=2*index+2,mid;
    45. if(left==leng-1) {//最后一个父节点为单亲节点
    46. if(arr[left]>arr[index]) {
    47. mid=arr[left];
    48. arr[left]=arr[index];
    49. arr[index]=mid;
    50. }
    51. }else {
    52. if(arr[left]>=arr[right]&&arr[left]>arr[index]) {
    53. mid=arr[left];
    54. arr[left]=arr[index];
    55. arr[index]=mid;
    56. }else if(arr[right]>=arr[left]&&arr[right]>arr[index]) {
    57. mid=arr[right];
    58. arr[right]=arr[index];
    59. arr[index]=mid;
    60. }
    61. }
    62. f3(arr,index-1,leng);
    63. }
    64. //大顶堆转顺序数组
    65. static void f4(int arr[],int leng) {
    66. if(leng==1)
    67. return;
    68. f3(arr,leng/2-1,leng);
    69. int mid=arr[leng-1];
    70. arr[leng-1]=arr[0];
    71. arr[0]=mid;
    72. leng--;
    73. f4(arr,leng);
    74. }
    75. public static void main(String[] args) {
    76. // TODO 自动生成的方法存根
    77. int arr[]= {5,2,8,9,2,6,7,10};
    78. // f1(arr,arr.length/2-1,8);
    79. f2(arr,8);
    80. // f3(arr,arr.length/2-1,8);
    81. // f4(arr,8);
    82. for (int i : arr) {
    83. System.out.print(i+" ");
    84. }
    85. System.out.println();
    86. }
    87. }

    8、计数排序

    思想:利用数组的特性,把元素值记录到新的辅助数组对应下标中,后顺序恢复即可(适用于元素较为集中的排序,如年龄、分数等)

    时间复杂度:O(n)

    稳定性:稳定

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main7 {
    4. //计数顺序排序(包含负数)
    5. static void f5(int[] arr) {
    6. int cur=0,max=0,min=0;
    7. for (int i : arr) {
    8. if(i>max)
    9. max=i;
    10. else if(i<-min)
    11. min=-i;
    12. }
    13. int[] helper=new int[max+1];
    14. int[] helper1=new int[min+1];
    15. for (int i : arr) {
    16. if(i>=0)
    17. helper[i]++;
    18. else
    19. helper1[-i]++;
    20. }
    21. for (int i = helper1.length-1; i > 0; i--) {
    22. while(helper1[i]>0) {
    23. arr[cur]=-i;
    24. helper1[i]--;
    25. cur++;
    26. }
    27. }
    28. for (int i = 0; i < helper.length; i++) {
    29. while(helper[i]>0) {
    30. arr[cur]=i;
    31. helper[i]--;
    32. cur++;
    33. }
    34. }
    35. }
    36. //方法二
    37. static void f5_1(int[] arr){
    38. int max=0,min=0,cur=0;
    39. for (int i : arr) {
    40. if(i>max)
    41. max=i;
    42. else if(i
    43. min=i;
    44. }
    45. for (int i = 0; i < arr.length; i++) {
    46. arr[i]-=min;//把所有负数转正数
    47. }
    48. int[] helper=new int[max-min+1];
    49. for (int i : arr) {
    50. helper[i]++;
    51. }
    52. for (int i = 0; i < helper.length; i++) {
    53. while(helper[i]!=0) {
    54. arr[cur]=i+min;//恢复原数组输出
    55. helper[i]--;
    56. cur++;
    57. }
    58. }
    59. }
    60. public static void main(String[] args) {
    61. // TODO 自动生成的方法存根
    62. // int arr1[]= {-3,2,4,-3,66,4,66,9,0,-90,2};
    63. // // f5(arr1);
    64. // f5_1(arr1);
    65. // System.out.println(Arrays.toString(arr1));
    66. }
    67. }

    9、桶排序

    思想:利用链表的特性,通过公式把数组分为多个数段的子链表(桶,元素进入链表时是有序插入),再顺序取出即可(计数排序的进阶版:浪费率相比更低、适用数据分布相比更广)

    时间复杂度:O(n)

    稳定性:稳定

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main7 {
    4. //桶排序(包含负数)
    5. static void f6(int[] arr) {
    6. int max=arr[0],min=arr[0],cur=0;
    7. for (int i : arr) {
    8. if(i>max)
    9. max=i;
    10. else if(i
    11. min=i;
    12. }
    13. List> bucketlist=new ArrayList<>();
    14. for (int i=0;i
    15. bucketlist.add(new LinkedList());//初始化桶
    16. }
    17. for (int i : arr) {
    18. int num=(i-min)*arr.length/(max-min+1);//最优公式,元素放置桶
    19. bucketlist.get(num).add(i);
    20. }
    21. for (LinkedList linkedlist:bucketlist) {
    22. Collections.sort(linkedlist);//归并排序桶中的集合
    23. }
    24. for (LinkedList linkedlist:bucketlist) {
    25. for (Integer integer : linkedlist) {
    26. arr[cur]=integer;//遍历输出
    27. cur++;
    28. }
    29. }
    30. }
    31. public static void main(String[] args) {
    32. // TODO 自动生成的方法存根
    33. // int arr1[]= {-3,2,4,-3,66,4,66,9,0,-90,2};
    34. // // f6(arr1);
    35. // System.out.println(Arrays.toString(arr1));
    36. }
    37. }

    10、基数排序

    思想:利用链表的特性,通过数字的位数(个-十-百…)渐进顺序分配到链表中,再顺序收集即可,直到最高位即整体有序(桶排序的进阶版)

    时间复杂度:O(n)

    稳定性:稳定

    1. package com.xch2.DiGui;
    2. import java.util.*;
    3. public class Main7 {
    4. //基数排序(包含负数)
    5. static void f7(int[] arr) {
    6. List[] bucketarr=new List[10];
    7. for (int i = 0; i < bucketarr.length; i++) {
    8. bucketarr[i]=new LinkedList();//初始化数组中的集合
    9. }
    10. int maxd=0,min=arr[0];
    11. for (int i:arr) {
    12. int len=(i+"").length();
    13. if(len>maxd)
    14. maxd=len;//找最大位数
    15. if(i
    16. min=i;//找最小值
    17. }
    18. if(min<0) {
    19. for (int i = 0; i < arr.length; i++) {
    20. arr[i]=arr[i]-min;//负数移位转正数
    21. }
    22. }
    23. int der=1,cur=0;
    24. for (int i = 1; i <= maxd; i++) {
    25. for (int j = 0; j < arr.length; j++) {
    26. int x=(arr[j]/der)%10;
    27. bucketarr[x].add(arr[j]);//入桶
    28. }
    29. for (int j = 0; j < bucketarr.length; j++) {
    30. for (Integer value : bucketarr[j]) {
    31. arr[cur]=value;//出桶
    32. cur++;
    33. }
    34. bucketarr[j].clear();
    35. }
    36. der*=10;
    37. cur=0;
    38. }
    39. if(min<0) {
    40. for (int i = 0; i < arr.length; i++) {
    41. arr[i]=arr[i]+min;//负数移位复原
    42. }
    43. }
    44. }
    45. public static void main(String[] args) {
    46. // TODO 自动生成的方法存根
    47. // int arr1[]= {-3,2,4,-3,66,4,66,9,0,-90,2};
    48. // // f7(arr1);
    49. // System.out.println(Arrays.toString(arr1));
    50. }
    51. }

    十大排序算法的时间复杂度:

    时间复杂度效率对比: 

  • 相关阅读:
    linux下基于boost/process库实现多进程管理,基于c++开发
    温敏传感器概述
    实例分割Yolact边缘端部署 (三) 从onnx到caffemodel
    VM虚拟机安装ikuai软路由系统
    不解压的情况下从各种压缩包中直接读取文本行内容
    23、JAVA进阶——日期操作类
    DETR纯代码分享(五)__init__.py(datasets)
    数据统计和分析怎么做?spss如何做好数据分析?
    2022年(第二届)信息技术服务业应用技能大赛网络与信息安全管理赛项的通知
    二维数组与稀疏数组转换(java)
  • 原文地址:https://blog.csdn.net/weixin_51091560/article/details/126920866