Mini-Notes: 数据结构与算法-[第三部分]排序

来源:互联网 发布:碧姬芭铎 知乎 编辑:程序博客网 时间:2024/06/10 06:56

前言
这个Mini-Notes开始于2016年4月18日下午,我想要认认真真把它写好,我也会认认真真把它写好。

排序的应用:

  1. 唯一性测试——如何测试一个给定序列S中的元素是否两两相异?
  2. 删除序列S中的重复元素
  3. 中位数(median element) / 第k小元素的选择
  4. 频率统计——哪个元素在序列S中出现的次数最多?
  5. Find closest pair
  6. 集合的交与并
  7. 寻找目标数对——给定一个目标数z,如何检测是否存在两个整数x,y属于S,使得x+y=z?

各种排序算法的比较分析:

各种排序算法的比较分析

排序算法一:插入排序(Insertion Sort)

基本思想:

就像我们打牌的时候整理纸牌一样,每次新拿到一个纸牌,就把它插入到前面的已经有序的纸牌里面的合适位置。

一个插入排序的例子:

3 2 6 1 5(原始序列)
2 3 6 1 5(整理3之后)
2 3 6 1 5(整理6之后)
1 2 3 6 5(整理1之后)
1 2 3 5 6(整理5之后)

排序算法二:选择排序(Selection Sort)

基本思想:

扫描左边的无序的部分,找到最大的值,然后交换这个位置与最后一个位置的值(也就是把最大的放到最后一个位置)。

一个选择排序的例子:

3 2 6 1 5(原始序列)
3 2 5 1 6(最大的是6)
3 2 1 5 6(最大的是5)
1 2 3 5 6(最大的是3)
1 2 3 5 6(最大的是2)
1 2 3 5 6(最大的是1)

排序算法三:希尔排序(Shell Sort)

一个希尔排序的例子:

一开始对increment = 5进行排序,也就是每隔5个元素比较一次,进行插入排序;然后对increment = 3进行排序,也就是每隔3个元素比较一次,进行插入排序;最后再进行increment = 1的插入排序。

一个希尔排序的例子

希尔排序的代码实现:

希尔排序的代码实现

又一个希尔排序的例子:

又一个希尔排序的例子

对希尔排序的算法分析:

开始时inc的值较大,子序列中的对象较少,排序速度较快;随着序列进展,inc值逐渐变小,子虚列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。
时间效率:
O(n1.25)~ O(1.6n1.25)——经验公式
空间效率:
O(1)——因为仅占用1个缓冲单元
算法的稳定性:
不稳定——因为49*排序后却到了49的前面

排序算法四:归并排序(Merge Sort)

归并排序是采用分治法(Divide and Conquer)的一个非常典型的例子。

基本思想:

  1. 如果序列的长度大于1,则把序列拆分为两个等长的子序列。
  2. 分别对两个子序列进行排序,使得这两个子序列内部是有序的。
  3. 合并两个有序的子序列为一个序列。

一个归并排序的例子:

一个归并排序的例子

归并排序的代码实现:

#include <iostream> // 归并排序 using namespace std;// 将两个有序子序列a[l, m]和a[m + 1, r]合并 void merge(int a[], int l, int m, int r, int t[]){    int lFirst = l;    int rFirst = m + 1;    int lLast = m;    int rLast = r;    int tIndex = 0;    while (lFirst <= lLast && rFirst <= rLast)    {        if (a[lFirst] <= a[rFirst])        {            t[tIndex] = a[lFirst];            lFirst++;        }        else        {            t[tIndex] = a[rFirst];            rFirst++;        }        tIndex++;    }    while (lFirst <= lLast)    {        t[tIndex] = a[lFirst];        lFirst++;        tIndex++;    }    while (rFirst <= rLast)    {        t[tIndex] = a[rFirst];        rFirst++;        tIndex++;    }    for (int i = 0; i < tIndex; i++)    {        a[l + i] = t[i];    }}void mergeSort(int a[], int l, int r, int t[]){    if (l < r)    {        int m = (l + r) / 2;        mergeSort(a, l, m, t); // 左边子序列有序         mergeSort(a, m + 1, r, t); // 右边子序列有序         merge(a, l, m, r, t); // 合并两个有序的子序列     }}int main(){    int n; // the number of elements in the array    cin >> n;    int a[n]; // the original array    for (int i = 0; i < n; i++)    {        cin >> a[i];    }    int t[n]; // the sorted array    mergeSort(a, 0, n - 1, t);    for (int i = 0; i < n; i++)    {        cout << a[i] << " ";    }    cout << endl;    return 0;} 

归并排序的应用:逆序对

逆序对:
对于一个包含N个非负整数的数组A[1, ..n],如果有i < j且A[i] > A[j],则称(i, j)为数组A的一个逆序对。
例如:
数组(3, 1, 4, 5, 2)的逆序对有(3, 1), (3, 2), (4, 2), (5, 2)共4个
枚举:
O(n2),n <= 5000适用

逆序对的代码实现:

int inverse_num = 0;void inverse_number(int* A, int x, int y, int* T){    if (y - x > 1)    {        int m = x + (y-x) / 2; // divide        int p = x, q = m, i = x;        merge_sort(A, x, m, T); // 递归求解        merge_sort(A, m, y, T); // 递归求解        while (p < m || q < y)        {            if (q >= y || (p < m && A[p] <= A[q]))            {                T[i++] = A[p++];            }            else             {                T[i++] = A[q++];                 reverse_num += m - p;                // 对于右边的每个q,统计左边比它大的元素个数            }        }        for(int i = x; i < y; i++)         {            A[i] = T[i];        }    }}

排序算法五:快速排序(Quick Sort)

基本思想:

两个指针left和right. left左边的都小于等于x, right右边的都大于x, 未知区域在中间
left和right交替移动,一旦发现不满足要求的元素就停下来.,交换这两个元素, 使同时满足要求。

好处:当相同元素比较多时较快

快速排序的一种做法

快速排序的代码实现:

#include <iostream> // 快速排序 using namespace std;int partition(int a[], int low, int high){    int pivot_item = a[low];    int left = low;    int right = high;    while (left < right)    {        // Move left while item <= pivot        while (a[left] <= pivot_item && left < high)        {            left++;        }        // Move right while item > pivot        while (a[right] > pivot_item && low < right)        {            right--;        }        if (left < right)        {            swap(a[left], a[right]);        }    }    // right is the final position for the pivot    a[low] = a[right];    a[right] = pivot_item;    return right;}void quickSort(int a[], int low, int high){    int pivot_position;    if (low < high)    {        pivot_position = partition(a, low, high);        quickSort(a, low, pivot_position - 1);        quickSort(a, pivot_position + 1, high);    }}int main(){    int n; // the number of elements in the array    cin >> n;    int a[n]; // the original array    for (int i = 0; i < n; i++)    {        cin >> a[i];    }    quickSort(a, 0, n - 1);    for (int i = 0; i < n; i++)    {        cout << a[i] << " ";    }    cout << endl;    return 0;} 
0 0