常见排序算法(c++实现)

常见排序算法(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)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
clipboard

动图演示:
归并
代码如下):

#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] << " ";
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值