常见排序算法(c++实现)
前言
一、排序介绍
二、算法实现
1.冒泡排序
原理:
冒泡排序顾名思义就是整个过程像气泡一样往上升,单向冒泡排序的基本思想是(假设由小到大排序):对于给定n个记 录,从第一个记录开始依次对相邻的两个记录进行比较,当前面的记录大于后面的记录时,交换位置,进行一轮比较和换位后,n个记录的最大记录将位于第n位,然后对前(n-1)个记录进行第二轮比较;重复该过程,直到记录剩下一个为止。
动图演示:
代码如下):
#include<iostream
using namespace std;
void BubbleSort(int list[],int n) {
for (int i = 0; i < n - 1; ++i) { //比较的循环数,有n个数,就比较n-1次;
for (int j = 0; j < n - i-1; ++j) {
if (list[j] > list[j + 1]) {
swap(list[j], list[j + 1]);
}
}
}
}
int main() {
int list[] = { 9,8,6,3,7,5,1 };
BubbleSort(list, 7);
for (int i = 0; i < 7; i++) {
cout << list[i] << ends;
}
return 0;
}
2.选择排序
原理:
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
动图演示:
代码如下):
#include<iostream>
using namespace std;
void SelectSort(int list[], int n) {
for (int i = 0; i < n-1 ; i++) {
int min = i;
for (int j = i+1; j < n; ++j) {
if (list[j] < list[min]) {
min = j;
}
}
swap(list[i],list[min]);
}
}
int main() {
int x[] = { 1,3,5,7,9,0,2,4,6,8 };
SelectSort(x, 10);
for (int i = 0; i <10; i++) {
cout << x[i] << ends;
}
return 0;
}
3.插入排序
原理:
插入排序始终在列表的较低位置维护一个排序的子列表,遇到新的项将它插入到原来的子列表,使得排序的子列表称为一个较大的项。
动图演示:
代码如下):
#include<iostream>
using namespace std;
void insertion_sort(int arr[], int len) {
for (int i = 1; i < len; i++) {
int key = arr[i];
int j = i - 1;
while ((j >= 0) && (key < arr[j])) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
int main() {
int list[] = { 9,8,6,3,7,5,1 };
insertion_sort(list, 7);
for (int i = 0; i < 7; i++) {
cout << list[i] << ends;
}
return 0;
}
4.希尔排序
原理:
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
动图演示:
代码如下):
#include<iostream>
using namespace std;
template<typename T>
void shell_sort(T array[], int length) {
int h = 1;
while (h < length / 3) {
h = 3 * h + 1;
}
while (h >= 1) {
for (int i = h; i < length; i++) {
for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
std::swap(array[j], array[j - h]);
}
}
h = h / 3;
}
}
int main() {
int list[] = { 9,8,6,3,7,5,1 };
shell_sort(list, 7);
for (int i = 0; i < 7; i++) {
cout << list[i] << endl;
}
return 0;
}
5.归并排序
原理:
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
动图演示:
代码如下):
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& arr, int L, int mid, int R)
{
vector<int> help(R - L + 1, 0);
int p1 = L, p2 = mid + 1, i = 0;
while (p1 <= mid && p2 <= R)
{
help[i++] = arr[p1] > arr[p2] ? arr[p2++] : arr[p1++];
}
while (p1 <= mid)
help[i++] = arr[p1++];
while (p2 <= R)
help[i++] = arr[p2++];
for (int i = 0; i < R - L + 1; i++)
{
arr[L + i] = help[i];
}
}
void sortprocess(vector<int>& arr, int L, int R)
{
if (L < R)
{
int mid = L + ((R - L) >> 1); // (L+R)/2
sortprocess(arr, L, mid);
sortprocess(arr, mid + 1, R);
merge(arr, L, mid, R);
}
}
void MergeSort(vector<int>& arr, int L, int R)
{
if (arr.size() < 2)
return;
sortprocess(arr, L, R);
}
int main()
{
vector<int> arr;
arr = { 9,8,6,3,7,5,1 };
MergeSort(arr, 0, arr.size() - 1);
for (int i = 0; i < arr.size(); i++)
cout << arr[i] << endl;
system("pause");
return 0;
}
6.快速排序
原理:
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想—-分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影。
动图演示:
代码如下):
#include<iostream>
#include<vector>
using namespace std;
void QuickSort(vector<double> &a, int left,int right) {
//一定要判断left<right,否则会导致stack overflow
if (left < right) {
int i = left;
int j = right;
double temp = a[i];
while (i < j) {
while (i < j && a[j] >= temp) {
j--;
}
a[i] = a[j];
while (i < j && a[i] <= temp) {
i++;
}
a[j] = a[i];
}
//退出时i==j
a[i] = temp;
QuickSort(a, left, i - 1);
QuickSort(a, i + 1, right);
}
else {
//此处为退出条件
return;
}
}
int main() {
vector<double> x= { 1,3.8,5,7,9.3,6,2,4.4,0,8};
QuickSort(x, 0, x.size()-1);
for (int i = 0; i <= 9; i++) {
cout << x[i] << " ";
}
return 0;
}
7.堆排序
原理:
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
动图演示:
代码如下):
优先队列实现堆排序
#include<iostream>
#include <queue>
using namespace std;
int main()
{
//对于基础类型 默认是大顶堆
priority_queue<int> a;
//等同于 priority_queue<int, vector<int>, less<int> > a;
// 这里一定要有空格,不然成了右移运算符↓↓
priority_queue<int, vector<int>, greater<int> > c; //这样就是小顶堆
priority_queue<string> b;//从大排到小
//小顶堆
// priority_queue<string,vector<string>,greater<string> > b;
for (int i = 0; i < 5; i++)
{
a.push(i);
c.push(i);
}
while (!a.empty())
{
cout << a.top() << ' ';
a.pop();
}
cout << endl;
while (!c.empty())
{
cout << c.top() << ' ';
c.pop();
}
cout << endl;
b.push("abc");
b.push("abcd");
b.push("cbd");
while (!b.empty())
{
cout << b.top() << ' ';
b.pop();
}
cout << endl;
return 0;
}
8.计数排序
原理:
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
算法描述:
- 找出待排序的数组中最大和最小的元素;
- 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
- 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
- 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。
动图演示:
代码如下):
优先队列实现堆排序
#include<iostream>
#include<vector>
using namespace std;;
void countingSort(vector<int>& arr, int maxValue = 100) {
vector<int>bucket(maxValue + 1, 0);
int = 0;
int arrLen = arr.size();
int bucketLen = maxValue + 1;
//入桶
for (int i = 0; i < arrLen; i++) {k
//if (!bucket[arr[i]]) {
// bucket[arr[i]] = 0;
//}
bucket[arr[i]]++;
}
//桶重排
for (int j = 0; j < bucketLen; j++) {
while (bucket[j] > 0) {
arr[k++] = j;
bucket[j]--;
}
}
return;
}
int main() {
vector<int> list = { 9,8,6,3,9,56,7,8,45,2,34,7,5,1 };
int l = list.size();
countingSort(list);
for (int i = 0; i < l; i++) {
cout << list[i] << " ";
}
}
9.桶排序
原理:
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)
算法描述:
- 设置一个定量的数组当作空桶;
- 遍历输入数据,并且把数据一个一个放到对应的桶里去;
- 对每个不是空的桶进行排序;
- 从不是空的桶里把排好序的数据拼接起来。
动图演示:
代码如下):
优先队列实现堆排序
#include<iostream>
#include<vector>
using namespace std;;
//冒泡排序
void BubbleSort(vector<int>& arr)
{
int tmp;
//对一维数组可以选择很多的排序算法,此处使用的冒泡排序
for (int i = 0; i < arr.size(); i++)
{
for (int j = 0; j < arr.size() - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
//桶排序
void bucketSort(vector<int>& arr, int bucketSize = 5) {
if (arr.size() == 0) {
return;
}
int i;
int minValue = arr[0];
int maxValue = arr[0];
//找到输入数据的最大最小值
for (i = 1; i < arr.size(); i++) {
if (arr[i] < minValue) {
minValue = arr[i];
}
else if (arr[i] > maxValue) {
maxValue = arr[i];
}
}
//计算桶的个数
int bucketCount = (int)((maxValue - minValue) / bucketSize) + 1;
vector<vector<int>>buckets(bucketCount, vector<int>());
// 利用映射函数将数据分配到各个桶中
for (i = 0; i < arr.size(); i++) {
int idx = (int)((arr[i] - minValue) / bucketSize);
buckets[idx].push_back(arr[i]);
}
arr.clear();
for (i = 0; i < buckets.size(); i++) {
//对每个桶内的数据进行排序
BubbleSort(buckets[i]);
for (int j = 0; j < buckets[i].size(); j++) {
arr.push_back(buckets[i][j]);
}
}
return;
}
int main() {
vector<int> list = { 9,8,6,3,9,56,7,8,45,2,34,7,5,1 };
int l = list.size();
bucketSort(list);
for (int i = 0; i < l; i++) {
cout << list[i] << " ";
}
}