冒泡排序、选择排序、直接插入排序、希尔排序、 归并排序、快速排序、堆排序
#include<string>
#include<vector>
#include<iostream>
using namespace std;
vector<int> maopaos(vector<int> &nums); /// 冒泡排序
vector<int> selects(vector<int> &nums); /// 选择排序
vector<int> inserts(vector<int> &nums); /// 插入排序
vector<int> shells(vector<int> &nums); /// 希尔排序
vector<int> guibins(vector<int> &nums); /// 归并排序
vector<int> quicks(vector<int> &nums); /// 快速排序
vector<int> heaps(vector<int> &nums); /// 堆排序
void printr(const string &name,const vector<int> &r) {
cout<< name <<" result: ";
for(auto &n : r) {
cout<<n <<",";
}
cout<<endl;
}
int main() {
{
vector<int> nums = {4, 2, 3, 6, 5};
auto res = maopaos(nums);
printr("maopao", res);
}
{
vector<int> nums = {4, 2, 3, 6, 5};
auto res = selects(nums);
printr("select", res);
}
{
vector<int> nums = {4, 2, 3, 6, 5};
auto res = inserts(nums);
printr("inserts", res);
}
{
vector<int> nums = {4, 2, 3, 6, 5};
auto res = shells(nums);
printr("shells", res);
}
{
vector<int> nums = {4, 2, 3, 6, 5};
auto res = guibins(nums);
printr("guibins", res);
}
{
vector<int> nums = {4, 2, 3, 6, 5};
auto res = quicks(nums);
printr("quicks", res);
}
{
vector<int> nums = {4, 2, 3, 6, 5};
auto res = heaps(nums);
printr("heaps", res);
}
return 0;
}
//*************************************************
/// 冒泡:比较相邻两个元素,如果第一个比第二个大,就交换(升序)
vector<int> maopaos(vector<int> &nums) { /// 冒泡排序
int n = nums.size();
if(n<2) return nums;
bool flag = true;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n-i-1; ++j) {
if(nums[j]>nums[j+1]) {
int tmp = nums[j+1];
nums[j+1] = nums[j];
nums[j] = tmp;
flag = false;
}
}
if(flag) break;
}
return nums;
}
//*************************************************
/// 选择排序:每次都从未排序部分中选择最小的元素放到未排序部分的最前面
vector<int> selects(vector<int> &nums) { /// 选择排序
int n = nums.size();
if(n<2) return nums;
for (int i = 0; i<n; ++i) {
int min_index = i;
for(int j = i+1; j < n; ++j) {
if(nums[j]<nums[min_index]) min_index = j;
}
if(min_index != i) {
int tmp = nums[min_index];
nums[min_index] = nums[i];
nums[i] = tmp;
}
}
return nums;
}
//*************************************************
///插入排序: 将当前访问的元素的前面部分当成是已经排好的序列,然后把当前元素插入到前面序列的合适位置
vector<int> inserts(vector<int> &nums) { /// 插入排序
int n = nums.size();
if(n<2) return nums;
for (int i = 1; i<n; ++i) {
int tmp = nums[i];
int j = i;
while(j>0 && nums[j-1]>tmp) {
nums[j] = nums[j-1];
j--;
}
if(j!=i) {
nums[j]=tmp;
}
}
return nums;
}
//*************************************************
/// 希尔排序:直接插入排序的优化,缩小增量排序。
vector<int> shells(vector<int> &nums) { /// 希尔排序
int n = nums.size();
if(n<2) return nums;
int gap = n/2;
while(gap > 0) {
for(int i = 0; i<n-gap; i++) {
int tmp = nums[i+gap];
if (tmp < nums[i]) {
nums[i+gap] = nums[i];
nums[i] = tmp;
}
}
gap = gap/2 ;
}
return nums;
}
//*************************************************
/// 归并排序:先将数组不断二分,知道各个子数组只包含一个元素,然后将各个子数组两两合并,
/// 合并后的序列是排序好的序列。然后再两两合并...知道恢复原本数组长度。
vector<int> merge(vector<int> left, vector<int> right) {
/// 合并两个升序数组,合并后的数组也是升序的!!!!!!!
int n1 = left.size(), n2 = right.size();
vector<int> ans(n1+n2);
int k1 = 0, k2 = 0, i = 0;
while(k1 < n1 && k2 < n2) {
if(left[k1] <= right[k2]) ans[i++] = left[k1++];
else ans[i++] = right[k2++];
}
while(k1 < n1) ans[i++] = left[k1++];
while(k2 < n2) ans[i++] = right[k2++];
return ans;
}
vector<int> guibins(vector<int> &nums) { /// 归并排序
int n = nums.size();
if(n<2) return nums; /// 递归结束条件
vector<int> left(nums.begin(), nums.begin() + n/2);
vector<int> right(nums.begin() + n/2, nums.end());
return merge(guibins(left), guibins(right)); // 递归!!
}
//*************************************************
/// 从数列中挑出一个元素,称为 “基准”(pivot);
/// 重新排序数列,所有元素比基准值小的摆放在基准前面,
/// 所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
/// 在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
/// 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
int partion(vector<int> &nums, int l, int r) { // 选基准值,并且排序
int pivot = l;
int index = pivot + 1;
for(int i = index; i <= r; ++i) {
if(nums[i] < nums[pivot]) {
/// 交换下标 i 和 index的值
swap(nums[i], nums[index]);
/// index加1,使得index下标总是指向一个大于基准数的值。
index++;
}
}
/// 交换基准值 和 大于他的序列的第一个值,交换后,基准值前面都是小于他的,后面都是大于他的。
swap(nums[pivot], nums[index-1]);
return index-1;
}
void quicksort(vector<int>& nums, int l, int r) {
if(l<r) {
int index = partion(nums, l, r);
quicksort(nums, l, index-1);
quicksort(nums, index+1, r);
}
}
vector<int> quicks(vector<int> &nums) { /// 快速排序
int n = nums.size();
if(n<2) return nums;
quicksort(nums, 0, n-1);
return nums;
}
//*************************************************
/// 升序排列
/// 堆排序,先建大顶堆,然后不断的把堆顶取走,再把堆尾放到堆顶,然后更新大顶堆。每次取走了都是剩余元素中最大的。
/// 注意 :数组实现二叉树,下标 k 的左子树节点下标为 2*k+1, 右子树节点下标 2*k+2。
/// 注意: 下标 i 的父节点下标为 (i-1)/2
/// 注意: 如果数组长度为 n , 那么下标大于 n/2 的节点都是 叶子节点。
/// nums的下标 0~heapsize-1 部分构成二叉树数组,对于树节点 k, 将 以k在以他为父节点的树中不断下沉。
void sink(vector<int> &nums, int heapsize, int k) {
int maxone = k; // 从此节点及其左右子节点中挑出最大值作为此节点。
int left = 2*k+1;
int right = 2*k+2;
if (left < heapsize) maxone = nums[maxone]<nums[left] ? left : maxone;
if (right < heapsize) maxone = nums[maxone]<nums[right] ? right : maxone; /// 注意决不能此处写成 right 跟 k 比。
if (maxone != k) {
std::swap(nums[k], nums[maxone]);
sink(nums, heapsize, maxone); // 继续下沉
}
}
/// 删除堆顶,并将其置于数组中二叉树序列的下一个元素。
void deletetop(vector<int> &nums, int &heapsize) {
std::swap(nums[0], nums[heapsize-1]);
heapsize--;
sink(nums, heapsize, 0); // 保证堆顶是二叉树中最大的元素
}
void buildheap(vector<int> &nums, int heapsize) {
int i = (heapsize-1)/2;
while(i>=0) {
sink(nums, heapsize, i);
i--;
}
}
vector<int> heaps(vector<int> &nums) { /// 堆排序
int n = nums.size();
if(n<2) return nums;
buildheap(nums, n);
int heapsize = n; /// 注意不能直接用n,因为以下 deletetop 会改变n 的值。
for(int i = 0; i < n-1; ++i) deletetop(nums, heapsize);
return nums;
}
//*************************************************
- 参考:
-
- https://mp.weixin.qq.com/s?__biz=MzUyNjQxNjYyMg==&mid=2247484184&idx=1&sn=62965b401aa42107b3c17d1d8ea17454&chksm=fa0e6c99cd79e58f298e9026f677f912bd8c8e55edb48fc509b2b5834f05e529a9b47d59d202&scene=21#wechat_redirect