Data Structures in C++:排序算法

主要参考:



交换

std::swap()可以直接使用,也可以自己实现:

template <class T>
void swap(const T& a, T const& b)
{
	T temp = a;
	a = b;
	b = temp;
}

关于const,值得说明的是:

  • const T x; 定义一个常量x,其值不可修改

  • const T* p; 定义一个指针变量p,其指向对象*p不可修改,指针p可修改
  • T const* p; 与上等同
  • T* const p = &var; 定义一个指针变量p,其指向对象*p可修改,指针p不可修改
  • const T* const p = &var; 定义一个指针变量p,其指向对象*p和指针p都不可修改

  • const T& a = var 定义一个引用变量a,其值不可修改
  • T const& a = var 与上等同
  • T& const a = var 无意义

  • bool empty() const; const修饰表明该成员函数不修改数据成员

冒泡排序

比较n-1趟,每趟比较n-i-1次,每次从头开始,大数逐次移到末尾.

template<class T>
void BubbleSort(T* a, int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 0; j < n - i - 1; j++)
        {
            if (a[j] > a[j + 1])
                swap(a[j], a[j + 1]);
        }
    }
}

选择排序

减少交换次数,只操作下标

template<class T>
void selectSort(T* a, int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        int min = i;
        for (int j = i + 1; j < n; j++)
        {
            if (a[min] > a[j])
                min = j;
        }
        if (min != i)
            swap(a[i], a[min]);
    }
}

插入排序

template<class T>
void insertSort(T* a, int n)
{
    for (int right = 1; right < n; right++)
    {
        int left = right - 1;
        T temp = a[right];
        while (temp < a[left] and left >= 0)
        {
            a[left + 1] = a[left];
            left--;
        }
        int middle = left + 1;
        a[middle] = temp;
    }
}

快速排序

递归的排序算法,平均时间 O ( n l o g n ) O(nlogn) 性能是目前最好的,应用最广泛; 但需要工作栈存放递归调用的执行环境,平均栈深 O ( l o g n ) O(logn) ,是一种不稳定的排序算法.

template<class T>
void quickSort(T* a, const int left, const int right)
{
    if (left >= right) return;  // 待排序数列只有一个元素时,结束递归
    else
    {
        // 选枢轴
        if (right - left == 1);
        else
        {   // 中值放在左侧
            int middle = (left + right) / 2;
            if (a[left] > a[middle])
                swap(a[middle], a[left]);
            if (a[middle] > a[right])
                swap(a[middle], a[right]);
            if (a[left] < a[middle])
                swap(a[middle], a[left]);
        }
        int pivot = left;

        // 一次划分
        int i{ left }, j{ right + 1 };
        while (i < j)
        {
            do i++; while (a[i] < a[pivot]);    // 从左扫描
            do j--; while (a[j] > a[pivot]);    // 从右扫描
            if (i < j) swap(a[i], a[j]);
        }
        swap(a[pivot], a[j]);                   // 最左侧为初始枢轴
        pivot = j;

        // 递归
        quickSort(a, left, pivot - 1);
        quickSort(a, pivot + 1, right);
    }
}

归并排序

引子
以下是两个有序数组a[ ], b[ ]的归并排序(最简单)
在这里插入图片描述

  • 递归式
    在这里插入图片描述
// 一次归并排序, 输入为已排序数组 a[l,...,m]  a[m+1,...,n]
template <class T>
void merge(T* a, const int l, const int m, const int n)
{
    // 申请辅助空间
    int length = n - l + 1;
    assert(length > 1);   // 消除C6386警告
    T* temp = new T[length];
    // 遍历等长元素              
    int i = l, j = m + 1, k = 0; 
    while (i <= m and j <= n)
    {
        if (a[i] <= a[j])
        {
            temp[k++] = a[i++];
        }
        else
        {
            temp[k++] = a[j++];
        }
    }
    // 复制其余元素
    copy(a + i, a + m + 1, temp + k);
    copy(a + j, a + n + 1, temp + k);
    // 释放辅助空间
    copy(temp, temp + length, a + l);
    delete[] temp;
}

template <class T>
void mergeSort(T* a, int left, int right)
{
    if (left >= right)
        return;
    int mid = (left + right) / 2;
    mergeSort(a, left, mid);
    mergeSort(a, mid + 1, right);
    merge(a, left, mid, right);
}
  • 迭代式
    在这里插入图片描述

以下代码的缺点:频繁申请/释放内存

// 一次归并排序, 输入为已排序数组 a[l,...,m]  a[m+1,...,n]
template <class T>
void merge(T* a, const int l, const int m, const int n)
{
    // 申请辅助空间
    int length = n - l + 1;
    assert(length > 1);   // 消除C6386警告
    T* temp = new T[length];
    // 遍历等长元素              
    int i = l, j = m + 1, k = 0; 
    while (i <= m and j <= n)
    {
        if (a[i] <= a[j])
        {
            temp[k++] = a[i++];
        }
        else
        {
            temp[k++] = a[j++];
        }
    }
    // 复制其余元素
    copy(a + i, a + m + 1, temp + k);
    copy(a + j, a + n + 1, temp + k);
    // 释放辅助空间
    copy(temp, temp + length, a + l);
    delete[] temp;
}

// 一趟归并排序
template <class T>
void mergePass(T* a, int n, int h)
{
    int i= 1;
    while (n - i + 1 >= 2 * h)
    {
        merge(a, i, i + h - 1, i + 2 * h - 1);
        i += 2 * h;
    }
    if (n - i + 1 > h)
        merge(a, i, i + h - 1, n);
    else
        ;// do nothing
}

// 归并排序(迭代式)
template <class T>
void mergeSort(T* a, int n)
{
    if (a == nullptr or n <= 0) return;
    // 最初归并长度为1
    for (int h = 1; h < n; h *= 2)
    {
        mergePass(a, n, h);
    }
}

改进:只申请一次内存

// 一次归并排序, 输入为已排序数组 a[l,...,m]  a[m+1,...,n]
template <class T>
void merge(T* a, T* result, const int l, const int m, const int n)
{
    // 遍历等长元素
    int i = l, j = m + 1, k = l;
    while (i <= m and j <= n)
    {
        if (a[i] <= a[j])
        {
            result[k++] = a[i++];
        }
        else
        {
            result[k++] = a[j++];
        }
    }
    // 复制其余元素
    copy(a + i, a + m + 1, result + k);
    copy(a + j, a + n + 1, result + k);
}

// 一趟归并排序
template <class T>
void mergePass(T* a, T* result, int n, int h)
{
    int i = 1;   
    while (n - i + 1 >= 2 * h)
    {
        merge(a, result, i, i + h - 1, i + 2 * h - 1);
        i += 2 * h;
    }
    if (n - i + 1 > h)
        merge(a, result, i, i + h - 1, n);
    else
        copy(a + i, a + n + 1, result + i);
}

// 归并排序(迭代式)
template <class T>
void mergeSort(T* a, int n)
{
    if (a == nullptr or n <= 0) return;
    T* temp = new T[n + 1];
    int h = 1;  // 最初归并长度为1
    while (h < n)
    {
        mergePass(a, temp, n, h);
        h *= 2;
        mergePass(temp, a, n, h);
        h *= 2;
    }
    delete[] temp;
}

猜你喜欢

转载自blog.csdn.net/Augurlee/article/details/104561570