博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
常见排序算法总结与实现(冒泡、插入、选择、希尔、堆排序、归并、快排)
阅读量:4648 次
发布时间:2019-06-09

本文共 6314 字,大约阅读时间需要 21 分钟。

本文使用Java实现这几种排序算法。

以下是对排序算法总体的介绍。

冒泡排序

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

时间复杂度:O(n^2),最优时间复杂度:O(n),平均时间复杂度:O(n^2)

public static void bubbleSort(Comparable[] a) {    int j, flag;    Comparable temp;    for (int i = 0; i < a.length; i++) {        flag = 0;        for (j = 1; j < a.length - i; j++) {            if (a[j].compareTo(a[j - 1]) < 0) {                temp = a[j];                a[j] = a[j - 1];                a[j - 1] = temp;                flag = 1;            }        }        // 如果没有交换,代表已经排序完毕,直接返回        if (flag == 0) {            return;        }    }}

插入排序

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤2~5

时间复杂度:O(n^2),最优时间复杂度:O(n),平均时间复杂度:O(n^2)

下面展示了两种插入排序的实现,第二种方法减少了交换次数。

public static void insertionSort(Comparable[] a) {    int length = a.length;    Comparable temp;    for (int i = 1; i < length; i++) {        for (int j = i; j > 0 && a[j].compareTo(a[j - 1]) < 0; j--) {            temp = a[j];            a[j] = a[j - 1];            a[j - 1] = temp;        }    }}
// 对实现Comparable的类型进行排序,先将大的元素都向右移动,减少一半交换次数
public static void insertionSort(Comparable[] a) {    int length = a.length;    Comparable temp;    int j;    for (int i = 1; i < length; i++) {        temp = a[i];        for (j = i; j > 0 && temp.compareTo(a[j - 1]) < 0; j--) {            a[j] = a[j - 1];        }        a[j] = temp;    }}

选择排序

首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。

时间复杂度:O(n^2),最优时间复杂度:O(n^2),平均时间复杂度:O(n^2)

public static void selectionSort1(Comparable[] a) {    int length = a.length;    int min;    Comparable temp;    for (int i = 0; i < length; i++) {        min = i;        for (int j = i + 1; j < length; j++) {            if (a[j].compareTo(a[min]) < 0) {                min = j;            }        }        temp = a[min];        a[min] = a[i];        a[i] = temp;    }}

希尔排序

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

时间复杂度:根据步长而不同,最优时间复杂度:O(n),平均时间复杂度:根据步长而不同

public static void shellSort(Comparable[] a) {    int length = a.length;    int h = 1;    Comparable temp;    while (h < length / 3) {        h = 3 * h + 1;    }    while (h >= 1) {        for (int i = h; i < length; i++) {            for (int j = i; j >= h && a[j].compareTo(a[j - h]) < 0; j -= h) {                temp = a[j];                a[j] = a[j - h];                a[j - h] = temp;            }        }        h /= 3;    }}

堆排序

  1. 创建最大堆(Build_Max_Heap):将堆所有数据重新排序
  2. 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算

时间复杂度:O(nlogn),最优时间复杂度:O(nlogn),平均时间复杂度:O(nlogn)

public static void heapSort(Comparable[] a) {    int length = a.length;    Comparable temp;    for (int k = length / 2; k >= 1; k--) {        sink(a, k, length);    }    while (length > 0) {        temp = a[0];        a[0] = a[length - 1];        a[length - 1] = temp;        length--;        sink(a, 1, length);    }}private static void sink(Comparable[] a, int k, int n) {    Comparable temp;    while (2 * k <= n) {        int j = 2 * k;        if (j < n && a[j - 1].compareTo(a[j]) < 0) {            j++;        }        if (a[k - 1].compareTo(a[j - 1]) >= 0) {            break;        }        temp = a[k - 1];        a[k - 1] = a[j - 1];        a[j - 1] = temp;        k = j;    }}

归并排序

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

时间复杂度:O(nlogn),最优时间复杂度:O(n),平均时间复杂度:O(nlogn),空间复杂度O(n)

自顶向下的归并排序

private static Comparable[] aux;// 自顶向下public static void mergeSort(Comparable[] a) {    aux = new Comparable[a.length];    mergeSort(a, 0, a.length - 1);}public static void mergeSort(Comparable[] a, int lo, int hi) {    if (hi <= lo) {        return;    }    int mid = (lo + hi) >>> 1;    mergeSort(a, lo, mid);    mergeSort(a, mid + 1, hi);    merge(a, lo, mid, hi);}public static void merge(Comparable[] a, int lo, int mid, int hi) {    int i = lo, j = mid + 1;    for (int k = lo; k <= hi; k++) {        aux[k] = a[k];    }    for (int k = lo; k <= hi; k++) {        if (i > mid) {            a[k] = aux[j++];        } else if (j > hi) {            a[k] = aux[i++];        } else if (aux[j].compareTo(aux[i]) < 0) {            a[k] = aux[j++];        } else {            a[k] = aux[i++];        }    }}

自底向上的归并排序

private static Comparable[] aux;// 自底向上public static void mergeSort(Comparable[] a) {    int length = a.length;    aux = new Comparable[length];    for (int sz = 1; sz < length; sz = sz + sz) {        for (int lo = 0; lo < length - sz; lo += sz + sz) {            merge(a, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, length - 1));        }    }}public static void merge(Comparable[] a, int lo, int mid, int hi) {    int i = lo, j = mid + 1;    for (int k = lo; k <= hi; k++) {        aux[k] = a[k];    }    for (int k = lo; k <= hi; k++) {        if (i > mid) {            a[k] = aux[j++];        } else if (j > hi) {            a[k] = aux[i++];        } else if (aux[j].compareTo(aux[i]) < 0) {            a[k] = aux[j++];        } else {            a[k] = aux[i++];        }    }}

快速排序

  1. 从数列中挑出一个元素,称为"基准"(pivot),
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

时间复杂度:O(n^2),最优时间复杂度:O(nlogn),平均时间复杂度:O(nlogn)

快排的时间复杂度跟选取基准的方法有关,一下是默认选择了第一个元素作为基准,随机性较大。

可以在序列中选取开始中间结尾三个数的中位数作为基准,进行优化。

public static void quickSort(Comparable[] a) {    quickSort(a, 0, a.length - 1);}public static void quickSort(Comparable[] a, int lo, int hi) {    if (hi <= lo) {        return;    }    int j = partition(a, lo, hi);    quickSort(a, lo, j - 1);    quickSort(a, j + 1, hi);}public static int partition(Comparable[] a, int lo, int hi) {    int i = lo, j = hi + 1;    Comparable temp;    Comparable v = a[lo];    while (true) {        while (a[++i].compareTo(v) < 0) {            if (i == hi) {                break;            }        }        while (v.compareTo(a[--j]) < 0) {            if (j == lo) {                break;            }        }        if (i >= j) {            break;        }        temp = a[i];        a[i] = a[j];        a[j] = temp;    }    temp = a[lo];    a[lo] = a[j];    a[j] = temp;    return j;}

 

转载于:https://www.cnblogs.com/alsf/p/6606287.html

你可能感兴趣的文章
对正则表达式又重新学了一遍,笔记方便以后查阅
查看>>
NSArray和NSString的联合使用
查看>>
UIKit应用 - Swift 版本: 3.让UITableViewCell的背景色渐变
查看>>
Java反射
查看>>
building tool
查看>>
JS中for循环输出三角形
查看>>
字节对齐2
查看>>
kafka幂等producer
查看>>
与Win8之磁盘活动时间100%斗争心得
查看>>
Matrix: android 中的Matrix (android.graphics.Matrix) (转)
查看>>
Android中处理崩溃异常
查看>>
Day7—socket进阶
查看>>
只读数据文件损坏恢复
查看>>
转过来的,可以看下
查看>>
windows搭建SVN服务MD版
查看>>
HashMap的工作原理
查看>>
一碗饭
查看>>
floyd求最小环 模板
查看>>
SqlServer索引的原理与应用
查看>>
使用Kubeadm搭建Kubernetes(1.12.2)集群
查看>>