HarmonyOS 6.0 常用算法可视化

HarmonyOS 6.0 常用算法可视化
在ArkTS里实现算法可视化核心问题不是算法本身——而是怎么让State驱动的UI正确响应数组变化。ForEach刷新机制、数组赋值触发、动画时序控制这些才是真正的坑。冒泡排序动画、二分查找过程、数据结构模拟一个个来看。State数组刷新机制这是ArkTS算法可视化最关键的前置知识。State装饰的数组直接修改元素不会触发UI刷新StatesortArray:number[][5,3,8,1,9];// 这样改不会刷新UIthis.sortArray[0]10;// 不行this.sortArray.push(7);// 不行this.sortArray.splice(0,1);// 不行// 必须整体替换this.sortArray[...this.sortArray,7];// 可以this.sortArraythis.sortArray.slice();// 可以(浅拷贝)letarrthis.sortArray.slice();arr[0]10;this.sortArrayarr;// 可以这个机制是声明式框架的基本原则——引用不变就不刷新。所有数组操作最终都要走重新赋值这条路。冒泡排序可视化冒泡排序是可视化入门最合适的算法——逻辑简单每次交换都能直观看到。关键是用setTimeout做逐步执行每一步更新状态让UI刷新StatesortArray:number[][5,3,8,1,9,2,7,4,6,0];Statecomparing:number[][];// 当前比较的索引对Statesorted:number[][];// 已排序的索引StateisSorting:booleanfalse;privatebubbleSort():void{if(this.isSorting){return;}this.isSortingtrue;this.sorted[];constarr:number[]this.sortArray.slice();// 工作副本letstep:number0;constdoStep():void{if(steparr.length-1){this.sortedarr.map((_v:number,i:number)i);this.comparing[];this.isSortingfalse;return;}this.comparing[step,step1];// 高亮比较对if(arr[step]arr[step1]){consttemp:numberarr[step];arr[step]arr[step1];arr[step1]temp;this.sortArrayarr.slice();// 触发UI刷新}step;setTimeout(doStep,200);// 200ms一步};doStep();}UI层用ForEach渲染柱状图颜色根据状态区分Row(){ForEach(this.sortArray,(item:number,index:number){Column(){Row().width(24).height(Math.max(item*8,4))// 高度映射数值.borderRadius(4).backgroundColor(this.sorted.indexOf(index)0?#43a047:// 绿已排序this.comparing.indexOf(index)0?#e53935:// 红比较中#1a73e8// 蓝默认)Text(item.toString()).fontSize(9).margin({top:2})}},(item:number,index:number)index.toString())}ForEach的key函数用index.toString()因为值可能重复。index在这里是稳定的排序过程中柱子位置变化是通过数组元素交换实现的不是DOM移动。二分查找过程可视化二分查找要求数组有序所以先排序再查找StatesearchTarget:number7;StatesearchResult:string;StatesearchSteps:number0;privatebinarySearch():void{constarr:number[]this.sortArray.slice().sort((a:number,b:number)a-b);this.sortArrayarr;// 更新为排序后的数组letlow:number0;lethigh:numberarr.length-1;letfound:booleanfalse;this.searchSteps0;while(lowhigh){this.searchSteps;constmid:numberMath.floor((lowhigh)/2);if(arr[mid]this.searchTarget){this.searchResult找到! 索引mid.toString() 步数this.searchSteps.toString();foundtrue;break;}elseif(arr[mid]this.searchTarget){lowmid1;}else{highmid-1;}}if(!found){this.searchResult未找到 步数this.searchSteps.toString();}}二分查找不需要动画化每一步执行太快了直接输出结果和步数就好。如果要做逐步动画同样用setTimeout闭包。时间复杂度O(log n)10个元素最多4步100个元素最多7步这是对数级增长的直观感受。数据结构在ArkTS中的实现ArkTS支持Array、Map、Set三种内置集合数组 — 万能基础constarr:number[][1,2,3];arr.push(4);// 末尾添加arr.pop();// 末尾删除arr.shift();// 开头删除arr.unshift(0);// 开头添加arr.splice(1,2);// 从索引1删2个arr.slice(1,3);// 取索引1-2的子数组arr.sort((a:number,b:number)a-b);arr.filter((x:number)x2);arr.map((x:number)x*2);arr.reduce((acc:number,x:number)accx,0);数组的坑State数组修改要重新赋值。另外ArkTS不支持Array.from的某些重载创建定长数组用循环// 创建0-9的数组constarr:number[][];for(leti0;i10;i){arr.push(i);}Map — 键值对constmap:Mapstring,numbernewMap();map.set(key1,1);map.get(key1);// 1 | undefinedmap.has(key1);// truemap.delete(key1);map.size;// 数量// 遍历map.forEach((value:number,key:string){console.info(keyvalue.toString());});Map的键可以是任意类型不像普通对象只能用string。但注意Map不能直接用在ForEach里——需要先转成数组。Set — 去重constset:SetnumbernewSet();set.add(1);set.add(2);set.add(1);// 重复不添加set.has(1);// trueset.delete(1);set.size;// 1去重是Set最常见的用途。数组去重constunique:number[][...newSet(arr)];队列 — 数组模拟ArkTS没有Queue类用数组模拟// 入队arr.push(item);// 出队constfront:number|undefinedarr.shift();shift()的时间复杂度O(n)因为要移动所有元素。数据量大时性能敏感场景需要考虑用双端实现或者环形缓冲区。不过UI层的数据量一般不大shift够用。栈 — 数组模拟// 入栈arr.push(item);// 出栈consttop:number|undefinedarr.pop();pushpop都在末尾操作O(1)没有性能问题。实际场景页面导航栈、撤销操作栈。动画时序控制算法可视化的核心难点是控制执行节奏。几种方案setTimeout递归最简单的方案每步之间固定延迟constdoStep():void{// 执行一步if(还有下一步){setTimeout(doStep,200);}};doStep();优点简单直观。缺点暂停/继续不好实现步间延迟固定。定时器标志位支持暂停的实现StateisPaused:booleanfalse;privatestepIndex:number0;privatetimer:number-1;startAnimation():void{this.timersetInterval((){if(this.isPaused){return;}this.executeStep(this.stepIndex);this.stepIndex;if(this.stepIndextotalSteps){clearInterval(this.timer);}},200);}togglePause():void{this.isPaused!this.isPaused;}setInterval的问题是不精确200ms间隔可能实际是210ms或230ms。但对可视化来说足够了。aboutToDisappear清理组件销毁时必须清理定时器aboutToDisappear():void{if(this.timer0){clearInterval(this.timer);}}不清理会导致内存泄漏和无效回调。随机数组生成测试用随机数组privaterandomize():void{constarr:number[][];for(leti0;i10;i){arr.push(Math.floor(Math.random()*20));}this.sortArrayarr;this.comparing[];this.sorted[];}Math.random()返回[0,1)的浮点数乘20取整得到0-19的整数。完整Demo结构一个算法可视化Demo的典型结构Tabs ├── 排序Tab │ ├── 柱状图(ForEach 状态色) │ ├── 控制按钮(随机/排序/重置) │ └── 日志区 ├── 查找Tab │ ├── 数组显示(高亮目标值) │ ├── 目标值输入 │ └── 查找按钮结果 └── 数据结构Tab ├── API说明 └── 代码示例三个Tab覆盖排序、查找、数据结构三大主题每个Tab独立状态互不干扰。性能考虑ForEach在数据量小时100项性能没问题大数据量排序可视化用LazyForEach柱状图高度计算用Math.max(value * 8, 4)确保最小可见indexOf在数组中查找O(n)复杂度小数组可接受setTimeout/setInterval的回调在UI线程执行不要做重计算算法可视化在ArkTS里最需要注意的始终是State刷新机制。写对算法逻辑只是第一步让每一步变化正确反映到UI上才是完整实现。重新赋值触发刷新这一条原则贯穿所有数组操作场景。