这三种简单排序算法 及其 mathematica 可视化
冒泡排序
算法思想
从未排序记录表的底部开始,依关键字逐次比较、交换相邻记录,将具有最小(大)键值的记录移至未排序记录表的顶部位置,直至记录表完全有序。
代码
void BubbleSort(SqTable &L ) {
for (i = L.len; i > 1; i--) {
for (j = 1; j < i; j++) {
if (L.r[j+1].key < L.r[j].key) swap(L.r[j], L.r[j+1]);
}
}
} //BubbleSort (升序)
算法分析
算法改进
我们可以判断序列是否有序,避免多余的比较。
void BubbleSortII(int a[], int n){
for (i=n-1,change=TRUE; i>0&&change; --i) {
change = FALSE;
for (j=0; j a[j+1]) {
swap(a[j],a[j+1]);
change = TRUE;
}
}
}//BubbleSortII
稳定度分析
可以想到,由于冒泡排序的每次交换都发生在相邻元素间,所以相等的两个元素的相对位置必然不会发生改变。
故,冒泡排序是稳定的。
可视化
a = RandomSample@Range[15]; len = Length[a];
res = {};
Do[Do[If[a[[j]] >
a[[j + 1]], ({{a[[j]], a[[j + 1]]}}) = ({{a[[j + 1]], a[[j]]}});
AppendTo[res, a]], {j, 1, len - i}], {i, 1, len - 1}]; ListAnimate[
BarChart[#, ChartStyle -> "Pastel",
ChartLegends -> ToString /@ #] & /@ res]
选择排序
算法思想
依关键字在未排序记录表中查找记录,选择具有最小(大)键值的 记录并与未排序记录表的首元素交换放置,直至记录表完全有序。
代码
void SelectSort (SqTable &L) {
for (i=1; i<L.len; ++i) {
lowIndex = i; //最小记录索引位置
for (k=i+1; k<=L.len; k++ )
if ( L.r[k].key < L.r[lowIndex].key )
lowIndex =k;
swap(L.r[i], L.r[lowIndex]); //交换记录
}
} //SelectSort
算法分析
稳定度分析
在移动最小/大键值的元素时,相等元素的相对位置可能改变,故选择排序是不稳定的。
可视化
插入排序
算法思想
从未排序记录表中逐次选取一个记录,依关键字将其与已排序子序列进行比较并插入至正确位置,直至记录表完全有序。
代码
/*对顺序表L作插入排序*/
void InsertSort (SqTable &L) {
for ( i=2; i<=L.len; ++i )
if ( L.r[i].key < L.r[i-1].key ){
L.r[0] = L.r[i]; // 复制为哨兵
for ( j=i-1; L.r[0].key<L.r[j].key; --j )
L.r[j+1] = L.r[j]; // 记录后移
L.r[j+1] = L.r[0]; // 插入到正确位置
}
} //InsertSort升序
稳定度分析
每次将一个元素插入已经排序好的序列中,相等的元素仍然按照初始时的先后顺序排列,相对位置没有发生改变。
故插入排序是稳定的。
算法分析
可视化
小结
三者中,只有选择排序是不稳定的。