当前位置:   article > 正文

数据结构与算法:排序算法_二、算法比较。设数组长度为n,插入排序的时间频度为t(n)=n*n,快速排序的时间频度

二、算法比较。设数组长度为n,插入排序的时间频度为t(n)=n*n,快速排序的时间频度

目录

排序

1、算法的时间复杂度

2、排序算法的时间复杂度

3、冒泡排序

4、选择排序

5、插入排序

6、希尔排序

7、快速排序

8、归并排序

9、基数排序


排序

排序也是一种算法

  • 内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序

  • 外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序

 

1、算法的时间复杂度

时间频度和时间复杂度

时间频度T(n)

一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。

时间复杂度O(n)

一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。

在T(n)=4n²-2n+2中,就有f(n)=n²,使得T(n)/f(n)的极限值为4,那么O(f(n)),也就是时间复杂度为O(n²)

  • 用常数1代替运行时间中的所有加法常数

  • 对于不是只有常数的时间复杂度忽略时间频度的系数、低次项常数

常见的时间复杂度

  • 常数阶 O(1)

int i = 1;
i++;

在执行上述代码时,它消耗的时间并不随变量 i 的增长而增长,那么无论代码执行了多少行,时间复杂度都是O(1)

  • 对数阶O(log2n)

while(i<n) {
    i = i*2;
}

此处i并不是依次递增到n,而是每次都以倍数增长。假设循环了x次后i大于n。则2x = n,x=log2n

  • 线性阶O(n)

  • 线性对数阶O(nlog2n)

for(int i = 0; i<n; i++) {
    j = 1;
    while(j<n) {
        j = j*2;
    }
}

此处外部为一个循环,循环了n次。内部也是一个循环,但内部f循环的时间复杂度是log2n

所以总体的时间复杂度为线性对数阶O(nlog2n)

  • 平方阶O(n²)

for(int i = 0; i<n; i++) {
    for(int j = 0; j<n; j++) {
        //循环体
    }
}
  • 立方阶O(n³)

  • k次方阶O(n^k)

  • 指数阶O(2^n) 要避免使用指数阶的算法

2、排序算法的时间复杂度

排序算法平均时间最差时间稳定性空间复杂度备注
冒泡排序O(n^2)O(n^2)稳定O(1)n较小时好
交换排序O(n^2)O(n^2)不稳定O(1)n较小时好
选择排序O(n^2)O(n^2)不稳定O(1)n较小时好
插入排序O(n^2)O(n^2)稳定O(1)大部分已有序时好
基数排序O(n*k)O(n*k)稳定O(n)二维数组(桶)、一维数组(桶中首元素的位置)
希尔排序O(nlogn)O(n^s)(1<s<2)不稳定O(1)s是所选分组
快速排序O(nlogn)O(n^2)不稳定O(logn)n较大时好
归并排序O(nlogn)O(nlogn)稳定O(1)n较大时好
堆排序O(nlogn)O(nlogn)不稳定O(1)n较大时好

3、冒泡排序

优化:如果在某次大循环,发现没有发生交换,则证明已经有序。所以可以添加flag标志位优化算法。

4、选择排序

算法步骤

  • 遍历整个数组,找到最小(大)的元素,放到数组的起始位置。

  • 再遍历剩下的数组,找到剩下元素中的最小(大)元素,放到数组的第二个位置。

  • 重复以上步骤,直到排序完成。

选择排序时间会比冒泡排序短一点

5、插入排序

算法步骤

  • 将待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列

  • 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面)

  1. public class Insertion {
  2. public static void InsertionSort(int[] array){
  3. for(int cur = 1; cur < array.length; cur++){
  4. int tmp = cur-1;
  5. int val = array[cur];
  6. while(val < array[tmp]){
  7. array[tmp+1] = array[tmp];
  8. tmp--;
  9. if(tmp == -1) break; //exception
  10. }
  11. array[tmp+1] = val;
  12. }
  13. }
  14. public static void InsertionSort(int[] array, int group){
  15. //int num = array.length/group;
  16. int i = 0;
  17. while(i < group){
  18. for(int cur = i+group; cur < array.length; cur += group){
  19. int tmp = cur - group;
  20. int val = array[cur];
  21. while(val < array[tmp]){
  22. array[tmp+group] = array[tmp];
  23. tmp -= group;
  24. if(tmp == i-group) break;
  25. }
  26. array[tmp+group] = val;
  27. }
  28. i++;
  29. }
  30. }
  31. public static void ShellSort(int[] array){
  32. int index = array.length/2;
  33. while(index > 0){
  34. InsertionSort(array, index);
  35. index /=2;
  36. }
  37. }
  38. public static void showValue(int[] array){
  39. for(int val : array){
  40. System.out.print(val + " ");
  41. }
  42. System.out.println();
  43. }
  44. public static void main(String[] args) {
  45. int[] array = {8,9,1,7,2,3,5,4,0};
  46. Insertion.showValue(array);
  47. Insertion.ShellSort(array);
  48. Insertion.showValue(array);
  49. }
  50. }

6、希尔排序

回顾:插入排序存在的问题

当最后一个元素为整个数组的最小元素时,需要将前面的有序数组中的每个元素都向后移一位,这样是非常花时间的。

所以有了希尔排序来帮我们将数组从无序变为整体有序再变为有序。

算法:

将数组分组(首先分数组长度/2 ... 直到最后分为一组),每次对小规模数组用插入排序,这样可以节约值交换的时间。

 

7、快速排序

算法:

  • 首先在数组中选一个基准数(通常为数组第一个)

  • 接着

     

  • 重复上述步骤直到 i==j ,将基准数和此位置数交换,于是得到一个左边比基准数小,右边比基准数大的数组

  • 将左右两边递归直到整个数组有序

    1. public class quickSort {
    2. public static void Sort(int[] array, int aFront, int aRear){
    3. if(aFront >= aRear) return;
    4. int midValue = array[aFront];
    5. int front = aFront;
    6. int rear = aRear;
    7. while(front < rear){
    8. while(array[rear] > midValue && rear > aFront){
    9. rear--;
    10. }
    11. while(array[front] <= midValue && front < aRear){
    12. front++;
    13. }
    14. if(front < rear){
    15. int tmp = array[front];
    16. array[front] = array[rear];
    17. array[rear] = tmp;
    18. }
    19. }
    20. array[aFront] = array[rear];
    21. array[rear] = midValue;
    22. Sort(array, aFront, rear-1);
    23. Sort(array, rear+1, aRear);
    24. }
    25. public static void showValue(int[] array){
    26. for(int val : array){
    27. System.out.print(val + " ");
    28. }
    29. System.out.println();
    30. }
    31. public static void main(String[] args) {
    32. int[] array = {11,2,10,2,11};
    33. quickSort.showValue(array);
    34. quickSort.Sort(array, 0, array.length - 1);
    35. quickSort.showValue(array);
    36. }

8、归并排序

算法步骤

归并排序用到了分而治之的思想,其难点是

  • 把数组从中间划分两个子数组

  • 一直递归地把子数组划分成更小的子数组,直到子数组里面只有一个元素

  • 依次按照递归的返回顺序,不断地合并排好的子数组,直到最后把整个数组的顺序排好。

在治的阶段,输入数组左右两边的位置left right。利用一个新的数组进行排序,最后再将排序好的数组赋值给原数组。

  1. public class MergeSort {
  2. public static void Sort(int[] array, int left, int right){
  3. int mid = (right + left)/2;
  4. if(left < right){
  5. Sort(array, left, mid);
  6. Sort(array, mid+1, right);
  7. Merge(array, left, right);
  8. }
  9. }
  10. public static void Merge(int[] array, int left, int right){
  11. int mid = (right + left)/2;
  12. int pointer1 = left;
  13. int pointer2 = mid + 1;
  14. int[] tmp = new int[right - left + 1];
  15. int index = 0;
  16. while(pointer1 <= mid && pointer2 <= right){
  17. if(array[pointer1] < array[pointer2]){
  18. tmp[index] = array[pointer1];
  19. index++;
  20. pointer1++;
  21. }else{
  22. tmp[index] = array[pointer2];
  23. index++;
  24. pointer2++;
  25. }
  26. }
  27. if(pointer1 <= mid){
  28. while(pointer1 <= mid){
  29. tmp[index] = array[pointer1];
  30. index++;
  31. pointer1++;
  32. }
  33. }else{
  34. while(pointer2 <= right){
  35. tmp[index] = array[pointer2];
  36. index++;
  37. pointer2++;
  38. }
  39. }
  40. for(int i=0; i <= right - left; i++){
  41. array[left + i] = tmp[i];
  42. }
  43. }
  44. public static void showValue(int[] array){
  45. for(int val : array){
  46. System.out.print(val + " ");
  47. }
  48. System.out.println();
  49. }
  50. public static void main(String[] args) {
  51. int[] array = {4,1,4,2,2,3,8,9,11,10,5,6,7,1};
  52. Sort(array, 0, array.length-1);
  53. showValue(array);
  54. }

9、基数排序

基本思想:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成了一个有序序列。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/511416
推荐阅读
相关标签
  

闽ICP备14008679号