本文将在可视化算法一(传送门)的基础上实现插入排序,其实就是多添加了一个实现插入排序的函数,再将Widget里的构造函数中的goBubble更换成goInsertion就可以了。
先介绍一下插入排序,先给俩个官方介绍的传送门(百度百科和Wiki对插入排序的介绍)
插入排序又可分为直接插入排序和折半插入排序,其中折半插入排序只是折半查找合适的位子。其实也可以结合扑克牌的理牌过程来理解。
直接插入排序(straight Insertion Sort)的基本操作时将一个记录擦汗如到已经排好序的有序表中,从而得到一个新的并且记录数增1的有序表。代码整体很简单,就是不断将较前者小的数插到有序表的合理位子。代码如下:
void Bubble::goInsertion()
{
//直接插入排序
for (int i = 1; i < length;i++) {
int j ;
if(data[i] < data[i - 1]){ //满足
int temp = data[i];
for (j = i - 1;j>= 0&&temp < data[j];j--) {//将比它大的数字往后挪一个位子
data[j+1] = data[j];
bubbleSignal(j);
QThread::msleep(static_cast<unsigned int>(mDelay));
}
data[j + 1] = temp;
bubbleSignal(j);
QThread::msleep(static_cast<unsigned int>(mDelay));
}
}
}
运行结果,由于我用的截取gif文件的上限时间是20ms,所以在这里设置的延时是10ms,导致有点快,还请见谅。
总结,本来还想接着实现以下折半插入算法,可是仔细想了想,折半插入是优化查找合适的位子,但数组还是得进行那么多挪位,那不如直接边挪位边判断位子合不合适呢,就没实现了,如果读者有意,可尝试实现。很容易看出插入算法的时间复杂度是O(n^2),具体介绍还得看上面俩个传送门的。
另外,我将Bubble类中rand函数修改了下,以免出现相同的数据
void Bubble::rand()
{
if(data == nullptr)
throw "数据不合理";
bool flag[length];
for(int i = 0; i < length; i++)
flag[i] = false;
for(int i = 0; i < length ; i++){
while(1){
int r = qrand()%max + 1;
if(flag[r-1] == false){
data[i] = r;
flag[r-1]= true;
break;
}
}
}
}