排序(1)---基础排序

基础排序

在排序算法中,我们需要计算比较交换的数量。对于不交换元素的算法,我们会计算访问数组的次数。在排序算法中额外的内存开销运行时间是同等重要的。
排序算法分为两类:1、除了函数调用所需要的栈和固定数目的实例变量之外无需额外内存的原地排序算法。
2、需要额外内存空间来存储另一份数组副本的其他排序算法。

一、选择排序

过程:找到数组中最小的数,和首位元素交换(如果首元素最小就和本身交换),然后依次找最小的元素交换。
特点:运行时间和输入无关。数据移动是最少的。
代码:
template<typename Item>
void eaxh(Item &a, Item &b)//交换代码
{
	Item t = a;
	a = b;
	b = t;
}

template <typename Item>
void selectsort(vector<Item> &a)//选择排序
{
	for (int i = 0; i < a.size(); i++)
	{
		int min = i;
		for (int j = i + 1; j < a.size(); j++)
			if (a[j] < a[min])  min = j;
		eaxh(a[i], a[min]);
	}
}

二、插入排序

插入排序所需要的时间取决于输入中元素的初始顺序。对一个很大且其中的元素已经有序(或接近有序)的数组进行排序将会比随机排序的数组或是逆序数组进行排序要快得多。
部分有序的数组:
1.数组中每个元素距离它的最终位置都不远;
2.一个有序的大数组接一个小数组;
3.数组中只有几个元素的位置不正确。
总的来说,插入排序对于部分有序的数组十分高效,也很适合小规模数组。

代码:
template<typename Item>
void insertsort(vector<Item> &a)//不带哨兵
{
	int N = a.size();
	for (int i = 1; i < N; i++)
		for (int j = i; j > 0 && a[j] < a[j - 1]; j--)
			eaxh(a[j], a[j - 1]);
}

template <typename Item>
void insertsort_1(vector<Item> &a)//a[0]为哨兵
{
	Item min = 0;
	int N = a.size();
	for (int i = 1; i < N; ++i)//寻找最小值,做为哨兵
		if (a[i] < a[min])min = i;
	eaxh(a[0], a[min]);
	for (int i = 1; i < N; ++i)
		for (int j = i; a[j] < a[j - 1]; --j)
			eaxh(a[j], a[j - 1]);
}

template <typename Item>
void insertsort_2(vector<Item> &a)//哨兵为a[n]
{
	a.push_back(INT_MAX);
	int n = a.size();
	for (int i = n - 2; i >= 0; --i)
		for (int j = i; a[j] > a[j + 1]; ++j)
			eaxh(a[j], a[j + 1]);
	a.pop_back();
}

template<typename Item>
void insertsort_3(vector<Item> &a)//数组移位方式插入
{
	int N = a.size();
	for (int i = 1; i < N; ++i)
	{
		Item temp = a[i];
		int j;
		for (j = i; j > 0 && temp < a[j - 1]; --j)
			a[j] = a[j - 1];
		a[j] = temp;
	}
}

template<typename Item>
void binaryinsertsort(vector<Item> &a)//折半插入排序
{//不停加入新元素,以折半查找的方式找到插入点,然后插入
	int N = a.size();
	for (int i = 1; i < N; ++i)
	{
		if (a[i] < a[i - 1])
		{
			Item temp = a[i];//哨兵
			int low = 0, high = i - 1;
			while (low <= high)//折半
			{
				int mid = (low + high) / 2;
				if (a[mid] < temp)low = mid + 1;
				else high = mid - 1;
			}
			for (int j = i; j > low; --j)//移位插入
				a[j] = a[j - 1];
			a[low] = temp;
		}
	}
}



三、冒泡排序
冒泡排序与插入排序及其相似,都是以交换为主的排序方式,不同点在于,插入排序是不停的新添加元素进行交换,而冒泡则是,一遍一遍的交换数组,使得元素“上沉下浮”。
代码:
template <typename Item>
void bubblesort(vector<Item> &a)
{
	int N = a.size();
	for (int i = 0; i < N - 1; ++i)
	{
		bool FF = false;//标志变量
		for (int j = N - 1; j > i; --j)
			if (a[j - 1] > a[j])
			{
				eaxh(a[j - 1], a[j]);
				FF = true;
			}
		if (FF == false)//没有交换,即排序完成
			return;
	}
}

四、测试:
测试用例:
int main()
{
	uniform_int_distribution<int> u(0, 100000);//随机用例
	default_random_engine e;
	vector<int> a;
	for (int i = 0; i < 10000; ++i)
		a.push_back(u(e));
	bubblesort(a);//被测试算法
	//for (auto c : a)//遍历结果
	//	cout << c << " ";
	//cout << endl;
	cout << (double)clock() / CLOCKS_PER_SEC << endl;//记录时间
	cout << endl;
	system("pause");
	return 0;
}
测试结果:
算法|量级10100100010000
选择排序0.1050.1070.1776.374
插入排序0.1060.1060.1745.792
移位插入排序0.1040.1050.1563.889
折半插入排序0.1060.1040.1382.636
冒泡排序0.1050.1060.2018.461

测试之后可以看出三种排序相差不大,其中插入排序稍微占优,又因为三种排序的空间需求都是1,所以在基础排序中选择插入为最佳。
而优化后的两种排序提升更是及为明显,折半的效果更好,当然代码量也更高。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值