这回尼奥要面对的,不是母体,而是一堆乱序的数字

17 阅读4分钟

建议先看视频, www.douyin.com/video/76021… 要不然,或许,不太好理解,吧?

无标题.png 【场景:一片漆黑的终端屏幕,墨菲斯(就是那个叫rocket的精灵)缓缓转过身,手里拿着几个大小不一的彩色圆球】

墨菲斯(画外音):
"这是你最后的机会。在这之后,就没有回头路了。如果你选择按Ctrl+C,故事结束,你在命令行里醒来,相信那些数据天生就是排好序的。但如果你选择编译运行...我会让你看看,冒泡排序的兔子洞有多深。"

【尼奥(也就是你)按下了回车键。突然,屏幕上炸开了一片彩虹】

墨菲斯:
"看好了,这些都C++结构体定义的是Node,每一个都是个小世界——里面有值(value),有位置(x),还有一个灵魂(Sprite* sp)。它们穿着不同颜色的衣服:红的、橙的、黄的...就像一群喝醉了酒、站成一排等待点名的小精灵。注意它们的身材——那个穿红衣服的,值只有30,瘦得像根筷子;那个穿紫衣服的,值200,胖得像个气球。"

【火箭精灵突然飞到画面中央,发出黄色的光芒】

墨菲斯:
"第一轮开始了...我们在遍历。看!左边这个胖子的值比右边大?交换! 看到了吗?不是瞬间移动,是慢一些的go(x,0)——它们真的在屏幕上滑步,像跳探戈一样互换位置。不只是屏幕上的动画,它们在内存里的datas数组中也 swap 了位置。这就是秩序的诞生,尼奥。"

【随着每一轮排序,火箭精灵都会大声报数】

墨菲斯:
"第二轮...第三轮...就像煮开水时气泡往上冒,最大的那个总是最先沉到右边。这就是冒泡排序的奥义——每一轮都会有一个'最大气泡'找到它的最终归宿。那些colors数组里的颜色?那只是为了让这场数字的华尔兹看起来更花哨一点。"

【最后,所有圆球整齐排列,从小到大,像军训过的士兵】

222.png

墨菲斯(收起光芒,写下最后一行字):
"演示完毕。你看,没有什么是真正混乱的,尼奥。只要有两层循环,一个if(datas[i]->value > datas[i+1]->value)的判断,再加上一点耐心(wait(1)),混沌就能变成秩序。现在...你还觉得矩阵只是0和1那么简单吗?"

【屏幕渐渐暗去,只留下一行小字:作者:李兴球】


简单说人话版:
这段代码就像是在电脑屏幕上搭了个舞台。它先用随机数造出5到8个彩色圆球(大小代表数值),然后让一个叫"火箭"的主持人一边报幕("第X轮开始啦"),一边指挥这些圆球玩"左边比右边大就换位子"的游戏。通过swap函数,圆球们不仅会交换数据,还会真的在屏幕上滑来滑去,让你肉眼看见冒泡排序是怎么把一堆乱序数字整理成一排的。最后所有圆球按大小站好队,火箭就说"下班啦",程序结束。

#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"};
void swap(int i,int j){   //交换两个节点
     Node *a = datas[i];
     Node *b = datas[j];   
     //交换a和b的x从标,并且到达自己的坐标    
     int tempx = a->x;
     a->x = b->x;
     b->x = tempx;
     a->sp->go(a->x,0);
     b->sp->go(b->x,0);
     //在datas中的位置也要交换
     Node *temp ;   
     temp = datas[i];
     datas[i] = datas[j];
     datas[j] = temp;     
}
int main(){        //主功能块 
   g_screen->bgcolor("black");
   int n= randint(5,8);
   int x = 50-100*n/2;    //最左边节点坐标(起始)
   for(int i=0;i<n;i++){    //建立n个节点,放到datas中
      int v = randint(30,200);
      Node *node = new Node;
      node->value = v;
      node->x = x;
      //按顺序选择索引为i的颜色,组合成角色的造型图片
      string s = "res/circle_" + colors[i] + ".png";
      Sprite *js = new Sprite(s); //新建角色,以s为造型
      js->scale(v/100.0);        //把角色缩小,要不然太大了
      js->penup();  js->go(x,0); js->speed(1); //定好起始位置
      node->sp = js;             //节点包含有角色指针
      datas.push_back(node);      
      x = x + 100;     //每个节点相差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();
   //真正的冒泡排序核心程序开始了
   for(int j=1;j<n;j++){  //排序的核心程序在这里
      string s = "第 " + to_string(j) + " 轮";    
      //删除最早写的文字,然后写上新的文字,并且等待1秒  
      rocket.cleartxts(1).write(s,42).wait(1);
      for(int i=0;i<n-j;i++)   
         if(datas[i]->value > datas[i+1]->value ) //发现更大的,则交换
             swap(i,i+1);
      rocket.wait(1);
   }
   rocket.cleartxts(1).write("演示完毕!",42).done();     //完成了
   return 0;    //返回0
}