1.题目
选择排序
2.数据结构与算法
algorithm:每次选择最大的元素放在末尾,以数值交换为基础完成该算法。
3.源代码
#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <list>
#include <algorithm>
using namespace std;
void selectionSort(list<int> &l){
list<int>::iterator tail = l.end();
list<int>::iterator head = l.begin();
list<int>::iterator max, p;
while(head != tail){
//选择最大值
max = head;
p = head;
while(p != tail){
if(*p >= *max){
max = p;
}
p++;
}
//最大值归位
swap(*max, *(--tail));
}
}
int main()
{
srand(time(NULL));
const int TEST_NUM = 100;
//初始化有序列表
list<int> l;
for(int i = 0; i < TEST_NUM; i++){
l.push_back(rand() % 10);
}
//遍历输出list
cout<<"input:"<<endl;
list<int>::iterator it;
for (it=l.begin(); it!=l.end(); it++){
cout<<*it<<" ";
}
selectionSort(l);
//遍历输出list
cout<<endl<<"output:"<<endl;
for (it=l.begin(); it!=l.end(); it++){
cout<<*it<<" ";
}
return 0;
}
4.时间复杂度
算法稳定性:
为了维持选择排序算法的稳定性,对于相同元素,我们总是选择最右侧的为max进行归位。
但对于本算法来说,这并不足够,因为本算法是基于值交换的,并没有发挥list本身的优势,基于值交换的选择排序算法依然是不稳定的。
举个例子:关注4与4* 的相对位置
5 4* 4
4 4* 5
排序动作:交换了位置0与位置2的数值。所以在排序前与排序后,其相对次序发生了改变,所以这种情况下SelectionSort是不稳定排序算法。
但是基于list本身的特性实现的选择排序算法是稳定的。
举个例子
5 4* 4
4* 4 5
排序动作:将位置0的Node拆下来,插入到位置2的后面。这样的机制实现的算法才是稳定的选择排序算法。(清华 DSA 邓俊辉 书中所给需要额外delete和new,这个时间耗费其实也是得不偿失的,可以考虑自己写一个算法:修改两Node的前驱和后继来实现。这样即不需要delete与new的时间耗费,同时又能保证算法的稳定性。)
时间复杂度:整个算法呈算数级数,需要 ο ( n 2 ) \omicron(n^2) ο(n2)的复杂度。
除此之外,你可能会想到,如果max已经就位,就无需再进行swap操作,你的第一想法可能是用if语句进行判断。然而从概率的角度来讲,max直接就位,这种概率发生是极低的。如果加了if语句,只会得不偿失,以下给出证明。
证明:
在各元素独立分布的情况下,max就位的概率和为调和级数
1
/
n
+
1
/
(
n
−
1
)
+
1
/
(
n
−
2
)
+
.
.
.
+
1
/
2
+
1
=
Θ
(
l
n
(
n
)
)
1/n +1/(n-1) + 1/(n-2)+ ...+1/2 +1=\Theta(ln(n))
1/n+1/(n−1)+1/(n−2)+...+1/2+1=Θ(ln(n))
就平均渐进意义上而言:
Θ
(
l
n
(
n
)
)
/
n
→
0
\Theta(ln(n))/n\rightarrow0
Θ(ln(n))/n→0
max直接就位,这种概率发生是极低的,使用if只会得不偿失。
5.结论
直接选择排序(SelectionSort)
1.基于list(转移结点)实现的SelectionSort是稳定的
2.基于值交换实现的SelectionSort是不稳定的
3.时间复杂度:
ο
(
n
2
)
\omicron(n^2)
ο(n2)
如有错误,请您批评指正。
参考书籍:清华大学《数据结构(C++语言版)》(第三版) 邓俊辉