十种排序算法集合

冒泡、选择、插入、希尔、快速、归并、堆、计数、桶、基数(升序为例)

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原理

堆分成两种大顶堆、小顶堆。

大顶堆:堆顶元素最大,父节点大于左右子节点
小顶堆:堆顶元素最小,父节点小于左右子节点

构造小顶堆,取小顶堆根节点数字,再构造小顶堆,依次递归。。。
堆排序方法:

  1. 先构造二叉树
  2. 再构造小顶堆堆,从叶子结点往上看,看左右子节点是否大于该节点,如果小于,就找最小的放在父节点,检查交换后的位置是否满足要求,再往下检查。
  3. 移出堆顶元素,将最下最右的元素移动到根节点,再构造大顶堆,依次递归至只有一个结点。

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是快排

2stable_sort

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值