选择排序:三种构建方法和非递归写法

选择排序

思想

将排序序列中的某元素作为基本值,按照该基本值将排序组合分成两个子序列,
左子序列均小于基准值,右子序列均大于基准值,然后左右序列重复这个操作,
直到数组有序为止。
确定基本值
//根据左值,右值,中值判断哪个位置的值为第二大的数,返回这个位置,将其作为基本数
int RealKey(int* a, int begin, int end)
{
	int mid = begin + ((end - begin) >> 1);
	
	if (a[mid] > a[begin])
	{
		if (a[begin] > a[end])
			return begin;
		else if (a[end] > a[mid])
			return mid;
	}
	
	if (a[mid] > a[end])
	{
		if (a[begin] > a[mid])
		{
			return mid;
		}
		else if (a[end] > a[begin])
		{
			return end;
		}
	}
	
	return begin;
}
常见的方法有:

1.交换法

int FastBuild1(int* a, int begin, int end)
{
	int key = RealKey(a, begin, end);

	swap(a[key], a[begin]);//将基本值和第一个数交换
	while (begin < end)
	{
		
		while (begin < end && a[end] > a[key])
		{
			end--;
		}

		while (begin < end && a[begin] <= a[key])//因为第一个数就是基本值,所以在a[begin] = a[key]的时候要begin++
		{
			begin++;
		}

		swap(a[begin], a[end]);//找到左边比基本值小的数和右边比基本值大的数,将其交换
	}
	swap(a[key], a[begin]);//跳出循环的时候,将第一个数和最后begin出现的位置进行交换
	return begin;

}

2.挖空法

int FastBuild2(int* a, int begin, int end)
{
	int key = RealKey(a, begin, end);
	int newkey = a[key];
	swap(a[begin], a[key]);//将基本值和第一个数交换
	while (begin < end)
	{
		while (begin < end && a[end] > newkey)
		{
			end--;
		}
		a[begin] = a[end];//将右边比基础值大的数给左边下标为begin的数

		while (begin < end && a[begin] <= newkey)
		{
			begin++;
		}

		a[end] = a[begin];//将左边比基础值小的数给右边下标为end的数
	}
	a[begin] = newkey;//最后下标为begin的位置空缺,将先前的临时值交换
	return begin;
}

3.双指针法

int FastBuild3(int* a, int begin, int end)
{
	int cur = begin + 1;
	int pur = begin;
	int sad = begin;
	while (cur <= end)
	{
		if (a[sad] > a[cur] && ++pur != cur)//注意&&是两个为真才为真,前后的判断语句是要执行的。
		{
			swap(a[pur], a[cur]);
		}
		cur++;
	}
	swap(a[sad], a[pur]);//最后交换sad下标和pur下标对应的数
	return pur;
}

递归写法

void QuickSort1(int*a, int begin, int end)
{
	if (begin >= end)
		return;
	int div = QuickBuilt3(a, begin, end);
	QuickSort1(a, begin, div-1);
	QuickSort1(a, div + 1, end);
}

非递归写法

非递归排序需要栈辅助,控制每次的FastBuild的范围。
void FastSort(int* a, int begin, int end)
{
	stack<int> s;
	s.push(end);
	s.push(begin);
	while (!s.empty())//判断条件为堆不为空
	{
		int left = s.top();
		s.pop();
		int right = s.top();
		s.pop();

		int div = FastBuild(a, left, right);//给定左右范围后,进行一次快速排序

		if (div - 1 > left)//构造左部分
		{
			s.push(div - 1);
			s.push(left);
		}

		if (div + 1 < right)//构造右部分
		{
			s.push(right);
			s.push(div + 1);
		}
	}

}

代码样例:

int main()
{
	int a[] = { 49, 38, 65, 97, 76, 13, 27, 49 };
	int n = sizeof(a) / sizeof(a[0]);
	int begin = 0;
	int end = n - 1;
	FastSort(a, begin, end);
	for (auto e : a)
	{
		cout << e << " ";
	}
	
	system("pause");
	return 0;
}

代码执行:
在这里插入图片描述
快速排序特点:
1.综合性能较好
2.时间复杂度O(n*logn)
3.空间复杂度O(logn)
4.稳定性:不稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值