#include<iostream>
#include<vector>
using namespace std;
//选择排序
//思路就是从前往后遍历,每个元素再次从本元素位置+1开始遍历,并和最小的交换
//用一个变量存最小值,注意要初始化为自身,因为就算不存在更小值也可以安全交换
//注意遇到相等的不要交换就可以保证稳定排序
//时间复杂度:O(N^2)--无论最好最坏都是
//空间复杂度:O(1)
void select_sort(vector<int>& v){
for (size_t i = 0; i < v.size()-1; ++i){
int idx = i;
for (size_t j = i + 1; j < v.size(); ++j){
if (v[j] < v[idx])//<=不稳定
idx = j;
}
if (v[idx]!=v[i])//去掉且<=才不稳定
swap(v[idx], v[i]);
}
}
void create_heap(vector<int>& v){
for (size_t i = 0; i < v.size(); ++i){
//i为当前插入节点
int cur = i;//当前插入节点可能会一直调整,所以要记录i
int parent = cur / 2;
while (v[cur]>v[parent]){
swap(v[cur], v[parent]);
cur = parent;
parent = cur / 2;
}
}
}
void put_down(vector<int>& v,int root,int num){
int left_child = root * 2 + 1;
int right_child = root * 2 + 2;
while (left_child < num){//如果左节点越界,右一定越界
int child;
if (v[left_child] < v[right_child] && right_child<num)//还需要判断右越界情况
child = right_child;
else
child = left_child;//只有左节点,没有右节点就是左节点,或者左节点大
//错误代码
//int child = v[left_child]>v[right_child] ? left_child : right_child;
if (v[root] < v[child]){
swap(v[root], v[child]);
}
else
break;
root = child;
left_child = root * 2 + 1;
right_child = root * 2 + 2;
}
}
//堆排序分为建堆+排序
//建堆就是在已确定数组的基础上开始调整,注意不是一边输入数据一边交换向上调整
//具体就是从0开始,和父节点比较并交换(等于就不交换),也是一个向上调整的过程(父节点=cur/2)
//需要注意的是排升序要建大堆,排降序建小堆
//因为建大堆最大的数据会在排序期间和最右子节点交换并固定,是一个先得到最大在逐级递减的过程,输出就是升序。
//
//排序的过程就是依次交换0和最大,堆顶向下调整,确定一个最右叶子结点
//这个最大节点从size-1一直到1,直到v[0]--v[1]交换就结束
//
//向下调整就是0号元素向下调整的过程,注意这个受到不断减小的最大值的影响(建议传参表示)
//逻辑就是若只有左节点就选择,都有就选择大的,都没有就跳过(用左节点做边界判断,再判断右是否存在和大小)
//确定孩子之后向下调整到cur大于等于孩子节点break
void heap_sort(vector<int>& v){
//建堆O(N)
//调整O(N*logN)--调整N-1次,每次lngN
//时间复杂度O(N*logN+N)=O(N*logN)
//不稳定
//1.建堆
create_heap(v);
int sz = v.size();
while (sz > 1){
//2.交换0和最大
swap(v[0], v[sz-1]);
--sz;
//3.向下调整0号元素
put_down(v, 0, sz);
}
}
//插入排序
//就是从1开始向后遍历,每个元素和前面的比较并让前面的向后覆盖,直到大于这个元素就放在他的下一个
//i为要插入的元素,j是已排序的最后一个,如果已排序的比待插入的大,后移
//平均时间复杂度:O(N^2)
//最坏情况复杂度:O(N^2)--反向有序
//最好情况复杂度:O(N)--有序
//空间复杂度:O(1)
//最多需要n(n−1)/2次比较
//最少需要n−1次比较
//稳定排序
//注意每一个要比较到比自己小的截止,要多算1个
void insert_sort(vector<int>& v){
for (size_t i = 1; i < v.size(); ++i){
int j = i - 1;
//j是已排序的最后一个,第一次也就是v[0],看作有序
int in_num = v[i];
for (; j >= 0; j--){
if (v[j]>in_num)
v[j + 1] = v[j];
else
break;
}
//j在执行完循环后后会执行第三段--变成-1;这个--i,i--没影响
v[j + 1] = in_num;
}
}
//希尔排序--升级插入排序(多了一层for用来传递间隔)
//平均时间复杂度:O(N*logN)~O(N^2)
//最坏情况复杂度:O(N^2)
//最好情况复杂度:O(N*logN)
//空间复杂度:O(1)
//不稳定排序
void shell_sort(vector<int>& v)
{ //初始间隔,每次少一半
for (int interval = v.size() / 2; interval > 0; interval /= 2)
{
for (size_t i = interval; i < v.size(); ++i)//++i
//从v[interval]开始往后遍历,将遍历到的数据与其小组进行插入排序
//第一个相当于有序,i是待插入的
{
int insert_num = v[i], j; //v[i]代表第一个,把他存起来等前面的覆盖
for (j = i - interval; j >= 0; j -= interval)//i-interval代表已排序最后一个
{
if (v[j] > insert_num)
v[j + interval] = v[j];
else
break;
}
v[j + interval] = insert_num;
}
}
}
void bubble_sort(vector<int>& v){
for (size_t i = 0; i < v.size() - 1; ++i){
for (size_t j = 0; j < v.size() - 1 - i; ++j){
if (v[j]>v[j + 1]){
swap(v[j], v[j + 1]);
}
}
}
}
//归并排序
void come(vector<int>& arr, int begin, int mid, int end){
vector<int> tmp = arr;
int begin1 = begin;
int end1 = mid;
int begin2 = mid + 1;
int end2 = end;
int idx = begin;
while (begin1 <= end1&&begin2 <= end2){
if (arr[begin1] <= arr[begin2])
tmp[idx++] = arr[begin1++];
else
tmp[idx++] = arr[begin2++];
}
if (begin1 <= end1)
while (begin1<=end1){
tmp[idx++] = arr[begin1++];
}
if (begin2 <= end2)
while (begin2<=end2){
tmp[idx++] = arr[begin2++];
}
arr = tmp;
}
//递归
void _merge_sort(vector<int>& arr,int begin,int end){
if (begin >= end)
return;
int mid = begin + (end - begin) / 2;
_merge_sort(arr, begin, mid);
_merge_sort(arr, mid + 1, end);
come(arr, begin, mid, end);
}
void merge_sort(vector<int>& arr){
int n = arr.size();
//子序列的步长
int step = 1;
while (step < n){
for (int idx = 0; idx < n; idx += 2 * step){
//[begin,mid] [mid+1,end]
int begin = idx;
int mid = idx + step - 1;
//不存在第二个子序列,直接跳过
if (mid >= n - 1)
continue;
int end = idx + 2 * step - 1;
//判断第二个子序列是否越界
//假如是9个元素,最顶层step为8,还是会进入循环
//但是最右多了一个,证明有第二序列不会continue
//但是最后一步合并8+1的时候end越界,就会出错(最后一个是随机数)
//最顶层也算是特殊情况
if (end > n)
end = n - 1;
come(arr, begin, mid, end);
}
//更新步长
step *= 2;
}
//递归
//int end = arr.size() - 1;
//_merge_sort(arr, 0, end);
}
//计数排序
//1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
//2. 时间复杂度:O(MAX(N, 范围))
//3. 空间复杂度:O(范围)
//4. 稳定性:稳定
void count_sort(vector<int>& v){
int big = v[0], small = v[0];
for (auto& e : v){
if (e > big)
big = e;
if (e < small){
small = e;
}
}
vector<int> count(big - small+1, 0);//注意要多一个内容
for (auto&e : v){
count[e - small]++; //把最小的放在0,依次递增,count数组中存放的是(num-small)数字的个数
}
int idx = 0;
for (size_t i = 0; i < count.size(); ++i){
while (count[i]--){ //再次输出到v数组里
v[idx++] = i+small; //遍历count数组,每次while直到不存在
} //注意插入的是索引+最小值
}
}
void test(){
vector<int> v = { 4, 6, 9, 7, 2, 5, 3, 1,8 };
shell_sort(v);
//bubble_sort(v);
//insert_sort(v);
//heap_sort(v);
//select_sort(v);
//_merge_sort(v,0,8);
//count_sort(v);
for (auto &e : v){
cout << e << endl;
cout << "---";
}
}
int main(){
test();
system("pause");
return 0;
}
快排:链接: link.