选择排序(重温经典算法系列)

:不要自我怀疑哈 :)

    • 原理简述
    • 直接选择排序算法
    • 双向选择排序算法
    • 参考材料






原理简述

默认首元素为最(大/小)值,接着与剩余元素逐一比较找出真正的最值元素;
中间过程的状态描述:
序列前段部分的元素有序,后段为待排序部分.
该假设之所以默认选择首元素位为最值,是为了遍历方便;
也可以默认最后一个元素位为最值,甚至是任一中间元素,只不过是需要修改对待排序区间的描述
(选择中间元素,则有可能使得简单问题变得复杂化).


直接选择排序算法


精炼代码

template <typename T>
void DirectSelectionSort(T* arr, const std::size_t n) {
	assert(arr);
	for (std::size_t i = 0; i < n - 1; ++i) {
		std::size_t minIndex = i;//升序;
		for (std::size_t j = i + 1; j < n; ++j) {	
			minIndex = arr[j] < arr[minIndex] ? j : minIndex;
		}
		if (minIndex != i) {
			std::swap(arr[minIndex], arr[i]);
		}
	}
}

代码草稿

//直接选择排序;
//最原始默认首元素为最(大/小)值,接着与剩余元素逐一比较找出真正的最值元素;
template <typename T>
//void DataSort::DirectSelectionSort(T* arr, const std::size_t n) {
void DirectSelectionSort(T* arr, const std::size_t n) {
	assert(arr);

	for (std::size_t i = 0; i < n - 1; ++i) {
		//for (std::size_t i = 0, j = i + 1; i < n - 1; ++i) {
		std::size_t minIndex = i;//升序时使用;
		//std::size_t maxIndex = i;//降序时使用;

		for (std::size_t j = i + 1; j < n; ++j) {
			//for ( j = i + 1; j < n; ++j) {
			if (arr[j] < arr[minIndex]) {
				//std::swap(arr[j], arr[i]);//该行代码会导致多余的元素交换操作,故而引入最值索引进行优化;
				minIndex = j;
			}
			//该if条件语句可修改成如下三目运算;
			//minIndex = arr[j] < arr[minIndex] ? j : minIndex;
		}
		if (minIndex != i) {
			std::swap(arr[minIndex], arr[i]);
		}
		/*std::cout << "DirectSelectionSort 当前序列: i = " << i << " j = " << j << " minIndex = " << minIndex << std::endl;
		RandomArrayFuntionHelper::PrintArray(arr, n);	*/
	}
}



双向选择排序算法


精炼代码

//双端选择排序;
template <typename T>
void HeadTailSelectionSort(T* arr, const std::size_t n) {
	assert(arr);
	for (std::size_t i = 0, j = i + 1; i < (n >> 1); ++i) {//位运算需要括号,不分有无符号;
		std::size_t minIndex = i;//该索引往左侧有序;
		std::size_t maxIndex = n - 1 - i;//该索引往右侧有序(初始值状态除外);
		if (arr[i] >= arr[n - 1 - i]) {
			std::swap(arr[i], arr[n - 1 - i]);
		}
		for (j = i; j < n - i; ++j) {
			minIndex = arr[j] < arr[minIndex] ? j : minIndex;
			maxIndex = arr[j] > arr[maxIndex] ? j : maxIndex;
		}
		if (minIndex != i) {
			std::swap(arr[minIndex], arr[i]);
		}
		if (maxIndex != n - 1 - i) {
			std::swap(arr[maxIndex], arr[n - 1 - i]);
		}
	}
}


温馨提示:
断言语句 assert(arr); 开头需要include头文件cassert(C++,即:
#include 

代码草稿

//双端选择排序;
template <typename T>
//void DataSort::HeadTailSelectionSort(T* arr, const std::size_t n) {
void HeadTailSelectionSort(T* arr, const std::size_t n) {
	assert(arr);

	//双端扫描,中间部分为无序区间,外层循环次数可减半;
	//for (std::size_t i = 0; i < n / 2; ++i) {
	////for (std::size_t i = 0, j = i + 1; i < n / 2; ++i) {
	for (std::size_t i = 0, j = i + 1; i < (n >> 1); ++i) {//位运算需要括号,不分有无符号;

		//假设最终要求数列升序,则应使得左小右大;
		//借助 i 实现两端索引向中间挪位,当然也可分别 ++minIndex 和 --maxIndex;
		std::size_t minIndex = i;//该索引往左侧有序;
		std::size_t maxIndex = n - 1 - i;//该索引往右侧有序(初始值状态除外);

		//首先要确保最大最小匹配:存在设计漏洞即——当最小索引所在位置即是所有元素的最大值时,会导致一轮刷选结果的最大索引获取的是第二大的值;
		//https://wenku.baidu.com/view/a6120c53bd64783e08122b2f.html;
		if (arr[i] >= arr[n - 1 - i]) { 
			std::swap(arr[i], arr[n - 1 - i]);
		}

		//for (std::size_t j = i + 1; j < n - i ; ++j) {
		for ( j = i ; j < n - i; ++j) {
			minIndex = arr[j] < arr[minIndex] ? j : minIndex;
			maxIndex = arr[j] > arr[maxIndex] ? j : maxIndex;
		}
		if (minIndex != i) {
			std::swap(arr[minIndex], arr[i]);
		}
		if (maxIndex != n - 1 - i) {
			std::swap(arr[maxIndex], arr[n - 1 - i]);
		}

		//参考文献:https://www.doc88.com/p-6816672556940.html
		/*std::cout << "HeadTailSelectionSort 当前序列: i = " << i << " j = " << j << " minIndex = " << minIndex << " maxIndex = "<< maxIndex << std::endl;
		RandomArrayFuntionHelper::PrintArray(arr, n);*/
		
	}
}


参考材料


双向选择排序算法参考文章:
两端选择排序算法

选择排序算法过程演示,请参考:
排序算法过程演示



交流方式
QQ —— 2636105163(南国烂柯者)
温馨提示:
转载请注明出处!!
2020年3月29日20:55:40

你可能感兴趣的:(程序设计进阶·算法设计)