栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

排序算法的C++实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

排序算法的C++实现

排序算法的C++实现

排序算法比较

1. 冒泡排序2. 选择排序3. 插入排序4. 希尔排序5. 归并排序6. 快速排序代码实现7. 堆排序

排序算法比较
排序方法时间复杂度(最好)时间复杂度(最坏)时间复杂度(平均)空间复杂度稳定性是否原地排序
冒泡排序O(n)O(n2)O(n2)O(1)稳定
选择排序O(n)O(n2)O(n2)O(1)不稳定
插入排序O(n)O(n2)O(n1.3)O(1)稳定
希尔排序O(n)O(n2)O(n2)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定不是
快速排序O(nlogn)O(n2)O(nlogn)O(1)不稳定

稳定性:如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变,则具备稳定性。

1. 冒泡排序

2. 选择排序

原理:在已给的序列中选择最大(最小)的数放到末尾,再从剩余元素中选择最大的,放到未排序的序列末尾,重复这个过程。直到全部排序完成。

选择排序每次都要找剩余未排序元素中的最小值,并和前面的元素交换位置,这样破坏了稳定性。比如 5,8,5,2,9 这样一组数据,使用选择排序算法来排序的话,第一次找到最小元素 2,与第一个 5 交换位置,那第一个 5 和中间的 5 顺序就变了,所以就不稳定了。正是因此,相对于冒泡排序和插入排序,选择排序就稍微逊色了。

3. 插入排序


原理:对于未排序序列,默认首元素是有序的,从后往前扫描已排序数据,将未排序元素依次插入到已经有序序列的对应位置。

4. 希尔排序


原理:希尔排序是将待排序的序列分成若干待排序的子序列,分别进行插入排序。关键在于间隔序列的设定。希尔排序是第一个突破O(n2)的排序算法。

5. 归并排序


原理:如果要排序一个数组,先将数组从中间分成前后两部分,对前后两部分分别排序,再将排好序的两部分合并在一起。

归并排序时间复杂度分析:
对n个数组进行归并的时间复杂度是T(n),分解成两个子数组进行排序的时间复杂的是T(n/2),合并有序数组的操作时间复杂度是O(n)。所以归并排序的时间复杂度就是:

T(n) = 2T(n/2) + n
= 2
(2T(n/4) + n/2) + n = 4T(n/4) + 2n
= 4
(2T(n/8) + n/4) + 2n = 8T(n/8) + 3n

= 2^k * T(n/2^k) + k * n

n/2^k 表示分解后的数据规模, k表示把数据规模分解到1时的分解次数,当算法完成,数据规模分解到1,此时n/2^k=1,k=log2n。将k带回原公式,可以计算得到T(n)=Cn+nlog2n,时间复杂度就是O(nlogn)。

6. 快速排序


原理:在数列中挑选一个数,称为基准(pivot),将比这个数小的元素放在左半边,其余元素放在右半边。递归地选择基准,并对两边的元素进行排序。

代码实现
#include
using namespace std;
#include
#include

//冒泡排序基础
void bubbleSort1(vector &q)
{
	for (int i = q.size() - 1; i > 0; i--)
	{ 
		for (int j = 0; j < i; j++)
		{
			if (q[j] > q[j + 1])
			{
				swap(q[j], q[j + 1]);
			}
		}
	}
}
//冒泡排序改进
void bubbleSort2(vector& q)
{
	for (int i = q.size() - 1; i > 0; i--)
	{
		bool flag = false;
		for (int j = 0; j < i; j++)
		{
			if (q[j] > q[j + 1])
			{
				swap(q[j], q[j + 1]);
				flag = true;
			}
		}
		//若内层循环没有进行一次交换说明已经有序,直接break
		if (!flag) break;
	}
}

//选择排序
void selectSort(vector& q)
{
	for (int i = 0; i < q.size(); i++)
	{
		//int max = q[i];
		for (int j = i + 1; j < q.size(); j++)
		{
			if (q[i] > q[j])
			{
				swap(q[i], q[j]);
			}
		}
	}
}

//插入排序
void insertSort(vector& q)
{
	for (int i = 1; i < q.size(); i++)
	{
		int t = q[i], j;
		for (j = i - 1; j >= 0; j--)
		{
			if (q[j] > t)
			{
				q[j + 1] = q[j];
			}
			else
				break;
		}
		q[j + 1] = t;

	}
}

//归并排序
//l,r分别代表区间的左右
void merges_sort(vector& q, int l, int r)
{
	if (l >= r) return; //只有一个元素

	int mid = (l + r) / 2;

	merges_sort(q, l, mid);  //左边做归并
	merges_sort(q, mid + 1, r); //右边做归并

	//归并操作
	static vector w; //辅助数组
	w.clear();

	int i = l, j = mid + 1;//两个指针指向两个序列的起点
	while (i <= mid && j <= r)
	{
		//判断当前两个指针指向的数哪个小
		if (q[i] < q[j])
		{
			w.push_back(q[i++]);
		}
		else
		{
			w.push_back(q[j++]);
		}
	}
	while (i <= mid) w.push_back(q[i++]);
	while (j <= r) w.push_back(q[j++]);

	for (int i = l, j = 0; j < w.size(); i++, j++)
	{
		q[i] = w[j];
	}
}

//快速排序
void quick_sort(vector& q, int l, int r)
{
	if (l >= r) return;
	int i = l - 1, j = r + 1, x = q[l + r >> 1];// x:基准,可以写成随机
	while (i < j)
	{
		do j--; while (q[j] > x); //大于x在右边
		do i++; while (q[i] < x); //小于x在左边
		if (i < j) swap(q[i], q[j]);
		else
			quick_sort(q, l, j), quick_sort(q, j + 1, r);
	}
}


int main()
{
	int n;
	vectorq;
	
	cin >> n;
	for (int i = 0, t; i < n; i++)
	{
		cin >> t;
		q.push_back(t);
	}

	//bubbleSort2(q);
	//selectSort(q);
	
	//insertSort(q);
	//merges_sort(q, 0, q.size() - 1);
	quick_sort(q, 0, q.size() - 1);
	for (auto x : q) cout << x <<' ';
	cout << endl;

	return 0;
}
7. 堆排序

堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/738042.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号