原理簡述
默認首元素爲最(大/小)值,接着與剩餘元素逐一比較找出真正的最值元素;
中間過程的狀態描述:
序列前段部分的元素有序,後段爲待排序部分.
該假設之所以默認選擇首元素位爲最值,是爲了遍歷方便;
也可以默認最後一個元素位爲最值,甚至是任一中間元素,只不過是需要修改對待排序區間的描述
(選擇中間元素,則有可能使得簡單問題變得複雜化).
直接選擇排序算法
精煉代碼
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<T>::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 <cassert>
代碼草稿
//雙端選擇排序;
template <typename T>
//void DataSort<T>::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