赞
踩
目录
十大经典排序算法包括:冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、堆排序、计数排序、基数排序 和 桶排序;
主要思想:视频讲解参考
每次将最大的元素移动到最后;
时间复杂度为 O (n^2);
- #include <iostream>
- #include <vector>
- #include <queue>
-
- class Solution{
- public:
- // 冒泡排序
- void bubSort(std::vector<int> &input){
- int len = input.size();
- while(--len){ // len 一开始指向最后一个元素
- for(int i = 0; i < len; i++){
- if(input[i] > input[i + 1]){
- int tmp = input[i];
- input[i] = input[i + 1];
- input[i + 1] = tmp;
- }
- }
- }
- }
- // 优化的冒泡排序
- void Better_bubSort(std::vector<int> &input){
- int len = input.size();
- int flag = 1;
- while(--len && flag){ // 当前面的已有序,即上一轮没有发生交换,就不会进入循环体
- flag = 0;
- for(int i = 0; i < len; i++){
- if(input[i] > input[i + 1]){
- flag = 1;
- int tmp = input[i];
- input[i] = input[i + 1];
- input[i + 1] = tmp;
- }
- }
- }
- }
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 3, 6, 4, 2, 5};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- S1.bubSort(input);
- S1.Print(input);
- return 0;
- }

主要思想:视频讲解参考
选择排序基于冒泡排序的思想,每一轮找到最小值(用 k 指向),将最小值与循环的第一个数(用 i 指向)交换,这样可以确保每一轮将最小值选择排序到前面;
时间复杂度为 O (n^2);
- #include <iostream>
- #include <vector>
- #include <queue>
-
- class Solution{
- public:
- // 选择排序
- void selectSort(std::vector<int>& input){
- int len = input.size();
- int k = 0; // 指向本次循环最小值的位置
- for(int i = 0; i < len; i++){
- k = i;
- for(int j = i + 1; j < len; j++){
- if(input[j] < input[k]) k = j; // 更新本次循环最小值的位置
- }
- int tmp = input[i];
- input[i] = input[k]; // 最小值的位置移动到前面
- input[k] = tmp;
- }
- }
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 3, 6, 4, 2, 5};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- S1.selectSort(input);
- S1.Print(input);
- return 0;
- }

主要思想:视频讲解参考
遍历每一个元素,将其插入到前面已经排好序的序列中,即与前面的数逐一比较,直到找到比其小的数,将元素插入到其后面;
时间复杂度为 O (n^2);
- #include <iostream>
- #include <vector>
- #include <queue>
-
- class Solution{
- public:
- // 插入排序
- void insertSort(std::vector<int>& input){
- int len = input.size();
- int key; // key表示本次循环中要插入的值
- for(int i = 1; i < len; i++){ // i 从 1 开始,因为input[0]已经是有序的
- key = input[i];
- int j = i-1; // 从前一个数开始比较
- while(j >= 0 && key < input[j]){ // 向前寻找,直到找到第一个比 key 小的数
- input[j+1] = input[j]; // 比较过的元素向后移动,因为要空出一个位置
- j--; // 继续向前寻找
- }
- input[j+1] = key; // 将 key 插入到第一个比它小的数的后面
- }
- }
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 3, 6, 4, 2, 5};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- S1.insertSort(input);
- S1.Print(input);
- return 0;
- }

主要思想:视频讲解参考
希尔排序是插入排序的进阶版,实质上是使用多次插入排序,只是每次插入比较的步长是step,当 step 为1时,希尔排序就退化为普通的插入排序;
希尔排序主要应用在数据量很大的排序问题中,本质上是减少交换的次数,因为当 step 退化为 1 时,序列已经大部分是有序的,所以交换的次数很少。
希尔排序的时间复杂度为:O(n^(1.3--2)),是一种不稳定的排序;
- #include <iostream>
- #include <vector>
- #include <queue>
-
- class Solution{
- public:
- // 希尔排序
- void shellSort(std::vector<int>& input){
- int len = input.size();
- //初始比较的 step 为 len/2,每一轮退化为 step/2;
- for(int step = len / 2; step > 0; step = step / 2){
- // 每一轮使用插入排序
- for(int i = step; i < len; i++){
- int key = input[i]; // 要插入的数
- int j = i - step; // 与前一个数进行比较
- while(j >= 0 && key < input[j]){
- input[j + step] = input[j];
- j = j - step; // 不断前移
- }
- input[j + step] = key;
- }
- }
- }
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 3, 6, 4, 2, 5};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- S1.shellSort(input);
- S1.Print(input);
- return 0;
- }

主要思路:
每次选定一个基准轴元素 (pivot),从两边开始扫描,比 pivot 小的元素放在轴的左边,比 pivot 大的元素放在轴的右边;
经过一次遍历之后,pivot 左边的元素都比 pivot 小,pivot 右边的元素都比 pivot 大,这样对于最终的结果来说,pivot 所在的位置是排好序的,只需递归排序 pivot 左边的元素和右边的元素即可;
快速排序的时间复杂度为:O(nlogn) ~ O(n^2)
- #include <iostream>
- #include <vector>
- #include <queue>
-
- class Solution{
- public:
- // 快速排序
- void quickSort(std::vector<int>& input, int left, int right){
- if(left >= right) return; // 递归结束条件
- int len = input.size();
- int pivot = input[left]; // 记录基准轴元素
- int i = left, j = right;
- while(i < j){
- while(i < j && input[j] >= pivot) j--; // 从右往左扫描直到找到第一个比 pivot 小的元素停下
- input[i] = input[j]; // 将小的数放到 pivot 的左边
- while(i < j && input[i] <= pivot) i++; // 从左往右扫描直到找到第一个比 pivot 大的元素停下
- input[j] = input[i]; // 将大的数放到 pivot 的右边
- }
- // 一趟遍历之后,将基准元素 pivot 放在 i 的位置(i == j)
- input[i] = pivot;
- // 递归排序pivot左边的元素和右边的元素
- quickSort(input, left, i - 1);
- quickSort(input, i+1, right);
- }
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 3, 6, 4, 2, 5};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- S1.quickSort(input, 0, input.size()-1);
- S1.Print(input);
- return 0;
- }

普通归并排序将两个有序的序列归并为一个有序的新序列;视频讲解
- #include <iostream>
- #include <vector>
-
- class Solution{
- public:
- std::vector<int> mergeSort(std::vector<int> input1, std::vector<int> input2){
- std::vector<int> Res;
- int i = 0, j = 0;
- while(i < input1.size() && j < input2.size()){
- if(input1[i] < input2[j]){
- Res.push_back(input1[i]);
- i++;
- }
- else{
- Res.push_back(input2[j]);
- j++;
- }
- }
- while(i < input1.size()){
- Res.push_back(input1[i]);
- i++;
- }
- while(j < input2.size()){
- Res.push_back(input2[j]);
- j++;
- }
- return Res;
- }
-
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input1 = {1, 3, 4, 6};
- std::vector<int> input2 = {2, 5, 7, 8};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input1);
- S1.Print(input2);
- std::cout << "After Sort: " << std::endl;
- std::vector<int> output = S1.mergeSort(input1, input2);
- S1.Print(output);
- return 0;
- }

进阶归并排序将一个无序的序列归并排序为一个有序的系列;通过递归将无序的序列二分,从底层开始将二分的序列归并排序为有序序列;
- #include <iostream>
- #include <vector>
-
- class Solution{
- public:
- // 归并排序
- std::vector<int> mergeSort(std::vector<int> input){
- std::vector<int> Res = split(input, 0, input.size() - 1);
- return Res;
- }
-
- // 二分序列
- std::vector<int> split(std::vector<int> input, int left, int right){
- if(left == right){ // 只剩下一个元素,返回由该元素构成的有序序列
- std::vector<int> Res = {input[left]};
- return Res;
- }
- int mid = left + (right - left) / 2;
- std::vector<int> input1 = split(input, left, mid);
- std::vector<int> input2 = split(input, mid+1, right);
- std::vector<int> Res = merge(input1, input2); // 二分至底层,进行归并排序再回溯
- return Res;
- }
-
- // 将两个有序的序列归并排序
- std::vector<int> merge(std::vector<int> input1, std::vector<int> input2){
- std::vector<int> Res;
- int i = 0, j = 0;
- while(i < input1.size() && j < input2.size()){
- if(input1[i] < input2[j]){
- Res.push_back(input1[i]);
- i++;
- }
- else{
- Res.push_back(input2[j]);
- j++;
- }
- }
- while(i < input1.size()){
- Res.push_back(input1[i]);
- i++;
- }
- while(j < input2.size()){
- Res.push_back(input2[j]);
- j++;
- }
- return Res;
- }
-
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 4, 6, 3, 5, 2, 8, 7, 10, 9, 11, 12};
-
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- std::vector<int> output = S1.mergeSort(input);
- S1.Print(output);
- return 0;
- }

关于堆的知识:从堆的定义到优先队列、堆排序(强烈推荐)
堆排序基本知识:视频讲解参考
① 堆排序中的堆分为大根堆和小根堆,小根堆中孩子结点的值必须大于父亲结点的值(即堆顶是最小值),大根堆中孩子结点的值必须小于父亲结点的值(即堆顶是最大值);
② 大根堆和小根堆本质上是一个完全二叉树,满足以下性质:结点连续存储,假设结点从0开始编号,则左孩子的位置为 2*parent + 1,右孩子的位置为 2*parent + 2;
③ (外堆且基于小顶堆)堆排序本质上分为入堆和出堆两步:
入堆时新加入结点,结点需要自底向上与父亲结点进行比较,重构大根堆和小根堆,确保满足上面的性质;
出堆时返回堆顶元素,并将最后一个元素放在堆顶位置,自顶向下与较小的孩子结点进行比较,重构大根堆和小根堆,确保满足上面的性质;
- #include <iostream>
- #include <vector>
- #include <queue>
-
- class Solution{
- public:
- void heapSort(std::vector<int>& input){
- int size = input.size();
- // 入堆
- for(int data : input){
- pushHeap(data);
- }
- // 出堆
- for(int i = 0; i < size; i++){
- input[i] = popheap();
- }
- }
-
- // 入堆
- void pushHeap(int data){
- if(len == 0){
- heap.push_back(data); // 入堆
- len++;
- return;
- }
-
- heap.push_back(data); // 入堆
- len++; // 元素个数 +1
-
- // 重新排序堆
- int cur = len - 1; // 当前堆中最后一个元素的位置
- int parent = (cur-1) / 2; // 父亲节点的位置
- while(parent != cur){ // 直到根节点
- if(heap[cur] < heap[parent]){
- swap(cur, parent); // 交换两个位置的值
- cur = parent;
- parent = (cur-1) / 2; // 从下往上比较,不断交换
- }
- else break;
- }
- }
-
- // 出堆
- int popheap(){
- int res = heap[0]; // 堆顶元素
- int cur = len - 1; // 最后一个元素的位置
- heap[0] = heap[cur]; // 最后一个元素的位置放到堆顶中
- len--; // 堆中元素 -1
- // 重新排序堆
- int start = 0;
- while(start <= len){ // 从根节点开始排序
- int l_child = 2*start+1;
- int r_child = 2*start+2;
- if(l_child > len || r_child > len) break; // 防止溢出
- int small = heap[l_child] < heap[r_child] ? l_child : r_child; // 较小的孩子
-
- if (heap[small] < heap[start]){ // 从上到下与较小的孩子交换位置
- swap(small, start);
- start = small;
- }
- else break;
- }
- return res;
- }
-
- void swap(int index1, int index2){
- int temp = heap[index1];
- heap[index1] = heap[index2];
- heap[index2] = temp;
- }
-
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
-
- private:
- std::vector<int> heap; // 小顶堆
- int len = 0; // 堆中元素的个数
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 3, 6, 4, 2, 5, 8, 7, 10, 9};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- S1.heapSort(input);
- S1.Print(input);
- return 0;
- }

在计数排序中,用一个数组的下标表示原数组的真值,数组下标对应的值表示真值出现的次数;遍历记录的数组,当下标对应的值不为0时,输入其下标(值多大就输出多少次);
在 C++ 中可以通过哈希表的形式来实现计数排序,key 表示原数组的真值,value 表示真值出现的次数;
经典利用数组实现计数排序可以参考视频讲解
- #include <iostream>
- #include <vector>
- #include <map>
-
- class Solution{
- public:
- std::vector<int> countSort(std::vector<int> input){
- for(int item : input){ // 遍历每一个数
- M.insert(std::pair<int, int>(item, M.count(item)+1));
- }
- for(auto item : M){ // map自动根据key排好序了,因此直接遍历即可
- int num = item.second; // 出现的次数
- while(num != 0){
- Res.push_back(item.first);
- num--;
- }
- }
- return Res;
- }
-
- // 打印函数
- void Print(const std::vector<int>& input){
- for(int item : input){
- std::cout << item << " ";
- }
- std::cout << std::endl;
- }
-
- private:
- std::map<int, int> M; // <真值,出现的次数>
- std::vector<int> Res;
- };
-
- int main(int argc, char *argv[]){
- std::vector<int> input = {1, 3, 6, 4, 2, 5, 8, 7, 10, 9};
- Solution S1;
- std::cout << "Before Sort: " << std::endl;
- S1.Print(input);
- std::cout << "After Sort: " << std::endl;
- std::vector<int> output = S1.countSort(input);
- S1.Print(output);
- return 0;
- }

在基数排序中,对每一个数依次按照个位、十位、百位 ... 来排序,对最高位排序后即为有序结果,返回即可;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。