《武林外传》之“插入排序”风云(采用C++精灵库制作的插入排序算法演示程序解说)

先看视频,更好理解:

插入排序算法可视化演示程序

(同福客栈内,灯火通明。白展堂手持算盘,佟湘玉坐镇柜台后,郭芙蓉挥着抹布,吕秀才捧着书摇头晃脑,李大嘴在厨房探出头来,莫小贝则趴在桌上画圈圈。)


佟湘玉 (拍桌而起):

"各位乡亲们!今天咱们不讲江湖恩怨,不聊儿女情长,而是要说------这'插入排序'的玄机!"

白展堂 (眯眼一笑):

"哟?排序?跟咱客栈排队打饭似的?"

郭芙蓉 (翻了个白眼):

"哼!要是这么简单,我早就把厨房那堆锅碗瓢盆排得整整齐齐了!"


第一幕:混乱初现

(此时,门口走进一群"彩色小球",个个圆滚滚、颜色各异,有的红得像辣椒,有的绿得像青菜,还有粉的像胭脂......它们摇摇晃晃地站成一排,位置乱七八糟。)

吕秀才 (推眼镜):

"此乃无序数组也!若不排序,何以治国平天下?"

莫小贝 (蹦跳上前):

"我来我来!看我把它们排成一条龙!"

佟湘玉 (拉住她):

"别急!排序有法,不可蛮干。今日我们要用的是------插入排序!"


第二幕:插入排序登场

白展堂 (模仿旁白腔调):

"话说这插入排序,就像你吃饭时夹菜------先夹一口尝味道,再决定放哪盘里。"

李大嘴 (从厨房探头):

"那我是不是也算'插入'?每次端菜都得找空位儿......"

众人 (齐声):

"闭嘴!做饭去!"


第三幕:实战演练

(场景切换:一个黑色屏幕浮现,上面漂浮着几个彩色小球,每个都标着数字,大小不一,高低错落。)

郭芙蓉 (指着最大的红球):

"这谁啊?一来就占C位!"

吕秀才 (解释):

"这是第一个元素,我们认为它是有序的起点。接下来每一个新来的,都要跟它比一比。"

白展堂 (掏出折扇,指向第二个黄球):

"来了第二位!数值30,个头不大,但脾气不小。现在要给他找个合适座位。"

(红球往后挪一个单位,然后橙球开始往前移动一个单位,于是它果断插队到前面。)

佟湘玉 (拍手叫好):

"看!这就是'插入'!找到位置,腾出空档,稳稳坐下!"


第四幕:高潮迭起

(第三个小黄球登场,数值10,身材苗小。)

莫小贝 (兴奋大喊):

"他又要比了!又要挪人了!"

(小黄球一路向前,发现红球太大,跳过;黄球太小,继续前进......最终停在最左位置。)

吕秀才 (感慨万千):

"人生如戏,全靠移位。每一次后退,都是为了更好的前进。"

白展堂 (突然严肃):

"注意!这不是普通的搬家,这是逻辑的胜利!每一步都稳扎稳打,绝不冒进!"


第五幕:尘埃落定

(所有小球依次归位,从小到大整齐排列,色彩斑斓却井然有序。)

郭芙蓉 (擦汗):

"终于排完了!比我练惊涛掌还累!"

李大嘴 (端菜出来):

"早说嘛,让我炒一盘'有序排列土豆丝'不就行了?"

众人 (再次齐声):

"滚回去炒菜!"


尾声总结

佟湘玉 (深情款款):

"插入排序之道,在于耐心与细致。取一人,观全局,步步为营,终得正果。"

白展堂 (收扇点头):

"正如江湖传言:从前有个数,它很孤独;后来学会了插入,从此不再迷路。"

全体演员谢幕鞠躬:

"谢谢观看!愿你的程序,也能像我们的客栈一样------越排越顺,越跑越快!"


插入排序口诀(附赠版)

我自前来,君且安坐;

若我不小,请你挪窝;

一路倒退,直到对位;

轻轻一插,完美收官!

cpp 复制代码
#include "sprites.h"  //包含C++精灵库 
using namespace std;
Sprite rocket;      //建立角色叫rocket
struct Node{
   int value,x;  //值和坐标
   Sprite *sp;
};
vector<Node *> datas;    //所有彩色圆形(节点)的指针存入这个向量
vector<string> colors = {"red","orange","yellow","green",
                         "cyan","blue","purple","pink"};
int startX;  // 记录起始x坐标
int step = 100;  // 每个节点之间的间隔

void movebackward(int j){ //把索引为j的节点后挪一个单位
   // 只需要更新节点的x坐标和精灵位置
   datas[j+1] = datas[j];   
   // 计算新位置
   int newX = startX + (j+1) * step;
   datas[j+1]->x = newX;
   datas[j+1]->sp->go(newX, -50);   
   // 添加短暂的延迟以便观察
   rocket.wait(0.2);
}

void placekey(int j, Node *key){  //放置key节点在索引j这里  
    datas[j] = key;    
    // 计算新位置
    int newX = startX + j * step;
    key->x = newX;
    key->sp->go(newX, -50);    
    // 添加短暂的延迟以便观察
    rocket.wait(0.2);
}

int main(){        //主功能块 
   g_screen->bgcolor("black");
   int n= randint(5,8);
   startX = 50 - 100*n/2;  // 保存起始坐标
   int x = startX;
   
   for(int i=0;i<n;i++){   //生成5到8个圆形,放到datas中
      int v = randint(30,200);
      Node *node = new Node;
      node->value = v;
      node->x = x;
      string s = "res/circle_" + colors[i] + ".png";
      Sprite *js = new Sprite(s);
      js->scale(v/100.0);
      js->penup();  js->go(x,-50); js->speed(1);
      node->sp = js;
      datas.push_back(node);      
      x = x + 100;
   }
   
   Sprite pen{"blank"}; 
   //pen.up().color(0).sety(300).write("插入排序算法可视化演示程序",50);
   //pen.color(30).sety(230).write("作者:李兴球,采用C++精灵库",30);
   //pen.color(60).sety(180).write("C++精灵库作者:李兴球",20);
   
   rocket.wait(1).color("yellow").penup().sety(130).hide();
   rocket.color("yellow").sety(130).write("开始排序...", 20);
   //建立指示器角色,它的方向向下,总是指向当前需要插入的节点
   Sprite ptr{"res/pointer_pink.png"};  //prt角色的造型是箭头
   ptr.penup().scale(0.6).right(90).sety(30).speed(1);
   // 插入排序算法
   for(int i=1; i<n; i++){
      ptr.setx(datas[i]->x);    //指示器到达当前需要寻找位置的角色的x位置
      datas[i]->sp->tremble(); //默认颤抖10次,实际效果为闪动,当前节点需要寻找合适的位置了 
      
      Node *key = datas[i];  // 保存当前key节点
      int j = i-1;
      
      // 从当前节点向前比较
      while(j>=0 && key->value < datas[j]->value){
         movebackward(j);   // 把索引为j的节点往后挪一个单位
         j--;
      }     
      placekey(j+1, key);  // 将key节点放入正确位置     
      rocket.wait(0.5);
   }   
   ptr.hide();
   rocket.cleartxts(1).write("演示完毕!",42).done();     //完成了
   
   return 0;    //返回0
}