13.排序综合

实验13 排序综合

代码

别问我为什么没有实验14, 堆排序也在这里了

#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::ostream;
using std::string;
using std::swap;

struct Element
{
    int key;
    string data;

    // 重载比较运算符, 方便后面直接元素对比
    bool operator<(const Element &rhs) const { return key < rhs.key; }
    bool operator<=(const Element &rhs) const { return key <= rhs.key; }
    bool operator>(const Element &rhs) const { return key > rhs.key; }
    bool operator>=(const Element &rhs) const { return key >= rhs.key; }
};

// 重载 << 用于输出数组类型
template <size_t N>
ostream &operator<<(ostream &os, const Element (&array)[N])
{
    for (const Element &e : array)
        cout << e.data << "(" << e.key << ")  ";
    return os;
}

// 冒泡排序
void bubble_sort(Element array[], int length)
{
    for (int i = 0; i < length - 1; i++)
    {
        bool has_swap = false; // 标记本轮是否发生元素交换, 没有说明排序已经完成
        for (int j = 0; j < length - 1 - i; j++)
            if (array[j] > array[j + 1])
            {
                swap(array[j], array[j + 1]);
                has_swap = true;
            }
        if (!has_swap)
            return;
    }
}

// 直接插入排序
void insert_sort(Element array[], int lenth)
{
    for (int i = 1; i < lenth; i++) // 从第二个元素开始
    {
        Element pop = array[i];                     // 弹出当前的元素
        int pre = i - 1;                            // 从它前面一个元素开始向前扫描
        for (; pre >= 0 && pop < array[pre]; pre--) // 如果扫到的元素比弹出的元素大
            array[pre + 1] = array[pre];            // 把这个元素后移一位
        array[pre + 1] = pop;                       // 所以比 pop 大的元素都移到后面了, 把 pop 放到空出来的位置
    }
}

// 折半插入排序
void insert_sort_bin(Element array[], int length)
{
    for (int i = 1; i < length; i++)
    {
        Element pop = array[i];
        int low = 0;
        int high = i - 1;
        int mid;
        while (low <= high)
        {
            mid = (low + high) / 2;
            if (array[mid] < pop)
                low = mid + 1;
            else
                high = mid - 1;
        }
        for (int j = i; j > low; j--)
            array[j] = array[j - 1];
        array[low] = pop;
    }
}

// 希尔排序
void shell_sort(Element array[], int lenth)
{
    for (int gap = lenth / 2; gap >= 1; gap /= 2)
    {
        for (int i = gap; i < lenth; i++)
        {
            Element pop = array[i];
            int pre = i - gap; // pre 本组的前一个元素
            for (; pre >= 0 && pop < array[pre]; pre -= gap)
                array[pre + gap] = array[pre];
            array[pre + gap] = pop;
        }
    }
}

// 简单选择排序
void selection_sort(Element array[], int length)
{
    for (int i = 0; i < length - 1; i++)
    {
        int min_index = i;
        for (int j = i + 1; j < length; j++)
            if (array[j] < array[min_index])
                min_index = j;
        swap(array[i], array[min_index]);
    }
}

// --------------- 快速排序 -------------------
// 对数组分区, 选择一个基准值 pivot, 它前面的元素小于它, 后面的元素大于它
// low、high 一开始指向数组的下界和上界
int partition(Element array[], int low, int high)
{
    Element pivot = array[low]; // 选择第一个作为基准值, 暂存起来
    while (low != high)         // low 指向数组最左, hight 指向最右, 如果他们没碰到
    {
        while (low != high && array[high] >= pivot) // high 从右往左扫描, 找到一个小于基准值的元素
            high--;
        array[low] = array[high];                  // 把找到的元素放到 low 指向的空位置
        while (low != high && array[low] <= pivot) // low 从左往右扫描, 找到一个大于基准值的元素
            low++;
        array[high] = array[low]; // 把它丢到右边 high 指向的位置(刚刚空出来了)
    }
    array[low] = pivot; // 此时 low 和 high 碰到一起了, 把基准值放到这里
    return low;
}

void quick_sort(Element array[], int low, int high)
{
    if (low >= high)
        return;

    int pivot_index = partition(array, low, high);
    quick_sort(array, low, pivot_index - 1);
    quick_sort(array, pivot_index + 1, high);
}

void quick_sort(Element array[], int length)
{
    quick_sort(array, 0, length - 1); // high 为最后一个元素的下标 length -1
}

// -------------- 堆排序 ---------------------------

// 把以 root 为根的子树调整为大根堆(根>=左、右孩子)
// 数组从 1 号位置开始放, root 的左孩子是 2*root, 右孩子是 2*root + 1
// 这里的数组从 0 号位置开始放, root 的左孩子是 2*root+1, 右孩子是 2*root + 2
void adjust_heap(Element array[], int root, int length)
{
    Element old_root = array[root];                       // 暂存 root 节点的值
    for (int i = 2 * root + 1; i < length; i = 2 * i + 1) // i 指向 root 节点的左孩子
    {
        if (i + 1 < length && array[i] < array[i + 1]) // 如果右孩子存在, 且比左孩子大
            i++;                                       // 让 i 指向右孩子

        if (old_root >= array[i])
            break; // 如果原 root 结点的值 >= 左右孩子中的最大者, 不用调整了

        array[root] = array[i]; // 否则, 把它换到 root 结点的位置
        root = i;               // 换过之后, 以 i 为根的子树可能不再是大根堆, 需要继续调整
    }
    array[root] = old_root; // 调整到最后, root 指到了正确位置, 它的父节点比它大, 子节点比它小, 原来的根节点就放到这里
}

// 建立一个大根堆
void build_max_heap(Element array[], int length)
{
    int last_branch_node = length / 2;          // 最后一个分支结点应该是 结点数 / 2, 往后就是叶子结点了
    for (int i = last_branch_node; i >= 0; i--) // 从后往前, 调整所有分支结点
        adjust_heap(array, i, length);
}

// 堆排序
void heap_sort(Element array[], int length)
{
    build_max_heap(array, length); // 把数组转成大根堆

    for (int i = length - 1; i > 0; i--) // 从数组最后一个元素开始往前扫
    {
        swap(array[0], array[i]); // 把大根堆的根节点(最大值)换到后面
        adjust_heap(array, 0, i);
    }
}

int main(int argc, char const *argv[])
{
    Element array[] = {{23, "小红"}, {88, "小米"}, {6, "小黑"}, {54, "小白"}, {76, "小绿"}};
    int length = 5;
    cout << "原始数组: " << array << endl;

    cout << "1.冒泡排序" << endl
         << "2.直接插入排序" << endl
         << "3.折半插入排序" << endl
         << "4.希尔排序" << endl
         << "5.简单选择排序" << endl
         << "6.快速排序" << endl
         << "7.堆排序" << endl;
    cout << "输入序号:";
    int choose;
    cin >> choose;
    switch (choose)
    {
    case 1:
        bubble_sort(array, length);
        break;
    case 2:
        insert_sort(array, length);
        break;
    case 3:
        insert_sort_bin(array, length);
        break;
    case 4:
        shell_sort(array, length);
        break;
    case 5:
        selection_sort(array, length);
        break;
    case 6:
        quick_sort(array, length);
        break;
    case 7:
        heap_sort(array, length);
        break;
    default:
        cout << "输入有误!" << endl;
    }

    cout << "排序结果:" << endl;
    cout << array << endl;
}

截图

posted @ 2020-12-01 19:15  zaxtyson  阅读(158)  评论(0编辑  收藏  举报