冒泡、选择、插入、希尔、快速、归并、堆、计数、桶、基数(升序为例)
文章目录
1快速排序
1.1思想
做二叉搜索树。选一个中心轴,把比这个值小的值放在左边,比这个值大的值放在右边。继续对左右子序列重复前三步操作。
关键就在于
pivot在排序之前就拿出来,空一个位置,然后左右指针交替扫描,遇到不符合情况的就把那个不符合的数字放到空位置,直至左右指针重合,在排序过程中pivot是一直在序列之外的,在一趟排序之后再把pivot放回唯一的空位置就行
1.3复杂度:
时间复杂度:最坏:从降序改升序O(n^2),最好:每次分为相等的一半O(nlogn)
空间复杂度:O(1)
1.4实现
递归+分治
//优化,编程模板形式,问题:迭代器类型怎么写成模板类型
bool compare(int a, int b) {
return a < b;
}
void quicksort(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
if (end - beg < 2) return;
int m = *beg;
auto l = beg, r = end - 1;
bool flag = 1;
while (l != r) {
//flag true 走右
if (flag) {
if (!compare(m,*r)) {
*l = *r;
flag = 0;
++l;
}
else --r;
}
else {
if (!compare(*l,m)) {
*r = *l;
flag = 1;
--r;
}
else ++l;
}
}
*l = m;
//左右排序
quicksort(beg, l);
quicksort(l + 1, end);
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " " ; });
std::cout<< std::endl;
std::cout <<test.end()-test.begin()<< std::endl;
quicksort(test.begin(), test.end());
std::cout << "After Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
2冒泡排序
2.1原理
不断比较相邻元素,如果左边元素大于右边,进行交换,直至满足要求顺序
2.2复杂度
时间复杂度 O(n^2)
空间复杂度O(1)
2.3 实现
递归/迭代
#include<iostream>
#include<vector>
#include<algorithm>
bool compare(int a, int b) { return a <= b; };
void bubblesort_diedai(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
bool flag = 0;
while (!flag) {
flag = 1;
for (auto iter = beg; iter < end-1; ++iter) {
if (!compare(*iter, *(iter + 1))) {
iter_swap(iter, iter + 1);
flag = 0;
}
}
}
}
void bubblesort_digui(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
bool flag = 1;
for (auto iter = beg; iter < end - 1; ++iter) {
if (!compare(*iter, *(iter + 1))) {
iter_swap(iter, iter + 1);
flag = 0;
}
}
if (!flag)
bubblesort_digui(beg, end);
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
std::cout << test.end() - test.begin() << std::endl;
bubblesort(test.begin(), test.end());
std::cout << "After Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
3选择排序
3.1原理
找到第i个最小的,与第i位交换
3.2复杂度
空间复杂度:O(n^2)
时间复杂度:O(1)
3.3实现
二重遍历
//这里给出顺序,注意判断时应在逆序时翻转
bool compare(int a, int b) { return a <= b; };
void selectionsort(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
for (auto iter_i = beg; iter_i < end; ++iter_i) {
auto temp = iter_i;
for (auto iter_j= iter_i; iter_j < end; ++iter_j) {
if (!compare(*temp, *iter_j)) {
temp = iter_j;
}
}
iter_swap(temp, iter_i);
}
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
std::cout << test.end() - test.begin() << std::endl;
selectionsort(test.begin(), test.end());
std::cout << "After Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
4 插入排序
4.1原理
不断将当前元素插入到升序序列中,直到所有元素都执行过插入操作
当前元素比之前元素大,就不动,否则找插入的位置插入(可以用二分法找插入位置)
4.2复杂度
时间复杂度O(n^2)
空间复杂度O(1)
4.3实现
//这里给出顺序,注意判断时应在逆序时翻转
bool compare(int a, int b) { return a <= b; };
//或者直接使用upper_bound插在小于该值的后边
std::vector<int>::iterator binary_getidx(std::vector<int>::iterator beg, std::vector<int>::iterator end, int num) {
auto l = beg, r = end - 1;
while (l <= r) {
auto m = l + (r - l) / 2;
if (compare(num, *m)) {
r = m - 1;
}
else {
l = m + 1;
}
}
return l;
}
//做增删迭代器会失效,所以使用下标
void insertsort(std::vector<int>& vec) {
for (auto i = 1; i < vec.size(); ++i) {
if (!compare(vec[i-1], vec[i])) {
//auto idx = upper_bound(vec.begin(), vec.begin()+i, vec[i], compare);
auto idx = binary_getidx(vec.begin(), vec.begin() + i, vec[i]);
auto vi = vec[i];
vec.erase(vec.begin()+i);
vec.insert(idx, vi);
}
}
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
std::cout << test.end() - test.begin() << std::endl;
insertsort(test);
std::cout << "After Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
5 归并排序
5.1原理
递归,先分两份排序向下递归,然后再双指针向上排好。
5.2复杂度
时间复杂度:O(nlogn)
空间复杂度:O(n),有一个辅助数组
5.3实现
#include<iostream>
#include<vector>
#include<algorithm>
//这里给出顺序,注意判断时应在逆序时翻转
bool compare(int a, int b) { return a <= b; };
void mergesort(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
int size = end - beg;
if (size == 1) return;
mergesort(beg, beg + size / 2);
mergesort(beg + size / 2, end);
auto l = beg, r = beg + size / 2;
std::vector<int> vi;
while (l != beg + size / 2 && r != end) {
if (compare(*l, *r)) {
vi.push_back(*l);
++l;
}
else {
vi.push_back(*r);
++r;
}
}
if (r != end) {
std::copy(vi.begin(), vi.end(), beg);
}
else {
std::vector<int> vi2(l, beg + size / 2);
std::copy(vi.begin(), vi.end(), beg);
std::copy(vi2.begin(), vi2.end(), beg+(vi.end()-vi.begin()));
}
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
std::cout << test.end() - test.begin() << std::endl;
mergesort(test.begin(), test.end());
std::cout << "After Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
6 希尔排序
6.1原理
是插入排序的变体,将数组分为i个分组,分组为增量,在组内采用插入排序。降低增量组数,再在组内排序。直至增量为1。
增量分组:设数组下标编号
0~n-1
,分为4gap组,则0~3+
【0、gap、2gap…】各为一组
目前增量大小的选择仍然是数学难题,建议以3x+1为组数进行排序,或者选择增量gap=length/2,缩小增量继续以gap = gap/2的方式。
6.2复杂度
时间复杂度:O(n^1.3~2),适合中等大小规模。
空间复杂度:O(1)
6.3实现
#include<iostream>
#include<vector>
#include<algorithm>
bool compare(int a, int b) { return a <= b; };
void shellsort(std::vector<int>& vi,int gap) {
//分组插入排序
for (int i = 0; i < gap; ++i) {
for (int j = i+gap; j < vi.size(); j = j + gap) {
int idx = j;
while (idx!= i && !compare(vi[idx - gap], vi[idx])) {
std::swap(vi[idx], vi[idx - gap]);
idx -= gap;
}
}
}
//降低增量继续希尔
if(gap>1) shellsort(vi, gap / 2);
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before sort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
std::cout << test.end() - test.begin() << std::endl;
shellsort(test,test.size() / 2);
std::cout << "After sort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
7计数排序
7.1原理
准备计数器数组,通过一次枚举,对原数组元素进行计数,从小到大枚举所有数,然后按位排序。
7.2复杂度
k:计数数组大小
时间复杂度:O(n+k)
空间复杂度:O(k)
7.3实现
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
//这里给出顺序,注意判断时应在逆序时翻转
bool compare(int a, int b) { return a < b; };
void countsort(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
//map计数
std::map<int,int,decltype(compare)*> mp(compare);
for (auto i = beg; i< end; ++i) {
if (mp.find(*i) == mp.end()) mp[*i] = 1;
else ++mp[*i];
}
auto iter = beg;
for (std::map<int,int,decltype(compare)*>::iterator idx = mp.begin(); idx != mp.end();++idx) {
std::fill(iter, iter + (idx->second), idx->first);
iter += idx->second;
}
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before countsort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
std::cout << test.end() - test.begin() << std::endl;
countsort(test.begin(), test.end());
std::cout << "After countsort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
8 基数排序
8.1 原理
取**每位(个十百千万)**根据位数放入对应数组/哈希表(容量为10,0~9)下标中进行排列,然后将他们根据从低到高的顺序放入队列中,递归至最大位数为止。
同理可得关键字排序(字典序),先排第一关键字,再排第二关键字,依次递归。。。
8.2 复杂度
n:n个数 k:最高k个位 时间复杂度:O(n*k)
空间复杂度:队列O(n),静态数组O(n*10)
8.3 实现
#include<iostream>
#include<vector>
#include<algorithm>
#include<deque>
#include<vector>
//按位compare方法
bool compare(int a, int b) { return a < b; };
void radixsort(std::vector<int>::iterator beg, std::vector<int>::iterator end,int bit) {
bool flag = 1;
std::deque<std::vector<int>> dq(10);
for (std::vector<int>::iterator iter = beg; iter != end; ++iter) {
int temp_bit = *iter/pow(10,bit);
temp_bit %= 10;
dq[temp_bit].push_back(*iter);
}
auto temp_iter = beg;
if (dq[0].size() == end - beg) flag = 0;
for (auto dq_i : dq) {
for (auto dq_j : dq_i) {
*temp_iter++ = dq_j;
}
}
if (flag) radixsort(beg, end, ++bit);
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "Before sort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
radixsort(test.begin(), test.end(),0);
std::cout << "After sort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
9 堆排序
9.1原理
堆分成两种大顶堆、小顶堆。
大顶堆:堆顶元素最大,父节点大于左右子节点
小顶堆:堆顶元素最小,父节点小于左右子节点
构造小顶堆,取小顶堆根节点数字,再构造小顶堆,依次递归。。。
堆排序方法:
- 先构造二叉树
- 再构造小顶堆堆,从叶子结点往上看,看左右子节点是否大于该节点,如果小于,就找最小的放在父节点,检查交换后的位置是否满足要求,再往下检查。
- 移出堆顶元素,将最下最右的元素移动到根节点,再构造大顶堆,依次递归至只有一个结点。
9.2复杂度
时间复杂度:O(nlogn)
空间复杂度:O(1)
9.3实现
bool compare(int a, int b) { return a >= b; }
std::vector<int>::iterator compare_iter(std::vector<int>::iterator iter_head, std::vector<int>::iterator iter_lchild, std::vector<int>::iterator iter_rchild) {
auto iter = compare(*iter_lchild, *iter_head) ? iter_head : iter_lchild;
iter = compare(*iter_rchild,*iter) ? iter : iter_rchild;
return iter;
}
void change(std::vector<int>::iterator iter_head, std::vector<int>::iterator iter_lchild
, std::vector<int>::iterator iter_rchild, std::vector<int>::iterator beg,std::vector<int>::iterator end) {
auto iter = compare_iter(iter_head, iter_lchild, iter_rchild);
while (iter != iter_head) {
iter_swap(iter_head, iter);
//从iter开始再往下判断
iter_head = iter;
iter_lchild = (iter - beg) * 2 + 1<end-beg?beg + (iter - beg) * 2 + 1:iter;
iter_rchild = (iter - beg) * 2 + 2 < end - beg ? beg + (iter - beg) * 2 + 2 : iter;
iter = compare_iter(iter_head, iter_lchild, iter_rchild);
}
}
void getheap(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
int s = end-beg;
auto temp_iter = beg + (end - beg -1);
//奇size,下标为偶
if (s == 1) return;
if (s & 1) {
auto r = temp_iter;
auto l = temp_iter-1;
auto h = beg + (temp_iter - beg) / 2 - 1;
change(h, l, r,beg,end);
temp_iter -= 2;
}
else {
auto l = temp_iter;
auto r = beg + (temp_iter - beg - 1) / 2;
auto h = r;
change(h, l, r,beg,end);
temp_iter --;
}
while (temp_iter != beg) {
auto r = temp_iter;
auto l = temp_iter-1;
auto h = beg + (temp_iter - beg) / 2 - 1;
change(h, l, r,beg,end);
temp_iter -= 2;
}
}
void heapsort(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
for (auto iter = beg; iter != end; ++iter) {
getheap(iter, end);
}
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,223,66,422,668,9,64,4 };
std::cout << "before sort:" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
heapsort(test.begin(),test.end());
std::cout << "after sort:" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
return 0;
}
10桶排序
10.1 原理
分多个均匀区间,将数放在每个区间中,区间内排序,然后再区间排序。
使用前提:
1.各个桶之间有序
2.桶之间数据是均匀分布,防止数据都在一个桶内
10.2复杂度
时间复杂度:n/mlog(n/m),n/m为桶中个数
空间复杂度:
10.3实现
#include<iostream>
#include<vector>
#include<algorithm>
//桶内部直接用sort排序了
bool compare(int a, int b) { return a <= b; };
void bucketsort(std::vector<int>::iterator beg, std::vector<int>::iterator end) {
int max_ele = *max_element(beg, end);
int bucketsize = 5;
int bucket = (max_ele+5) / 5;
auto temp = beg;
std::vector<std::vector<int>> bucket_arr(5);
for (auto iter = beg; iter != end; ++iter) {
bucket_arr[( * iter) / bucket].push_back(*iter);
}
for (auto arr : bucket_arr) {
sort(arr.begin(), arr.end());
std::copy(arr.begin(), arr.end(),temp);
temp += (arr.end() - arr.begin());
}
}
int main() {
std::vector<int> test = { 2,5,7,4,3,8,6,5,9,20,66,30,45,9,50,4 };
std::cout << "Before Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
std::cout << test.end() - test.begin() << std::endl;
bucketsort(test.begin(), test.end());
std::cout << "After Quicksort" << std::endl;
for_each(test.begin(), test.end(), [](int i) {std::cout << i << " "; });
std::cout << std::endl;
}
汇总
11C++排序
1 sort
sort排序
对于c++:sort是快排