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;
}