我用js寫了一個冒泡排序法,怎麼用html和css把排序過程展現出來?


具體怎麼實現都不說,答什麼題。

使用 HTML 實現排序過程,就是把排序的每一步的狀態同步到 DOM 上。如果要實現可視化效果,要求每一步排序是定時順序執行的。核心的難點是如何將排序過程「暫停」。

下面是一個正常的冒泡排序結構:

for(i) {
for(j) {
// 輸出當前狀態到 DOM
}
}

你可以把你的排序演算法改成回調加定時器的方式,但是這樣你可能會把你原來的幾層循環嵌套改得面目全非。

JavaScript 中,有 co + generator 或者 async/await 「同步」方案,藉助 babel 可以編譯成 es5。正好適合這種需求。

我簡單寫了個 Demo,地址為:http://meowtec.github.io/demo/sort-v/.

下面是排序可視化的部分源碼,可以看到它的邏輯和結構和原始的排序演算法幾乎沒有變化。

async sort() {
for (var j = 0; j &< this.count; j++) { let finish = true for (var i = 0; i &< this.count - j - 1; i ++) { // 獲取數字 var a = this.getNumber(i) var b = this.getNumber(i + 1) this.info(`比較${a}和${b}`) this.style(i, "active") this.style(i + 1, "active") await sleep(1000) if (a &> b) {
finish = false
this.info(`${a}比${b}要大,需要交換`)
this.style(i, "light")
this.style(i + 1, "light")
await sleep(1000)
// 交換 i 和 i + 1
this.exchange(i, i + 1)

await sleep(1000)
}
else {
this.info(`${a}不比${b}大,跳過`)
await sleep(1000)
}

this.unstyle(i)
this.unstyle(i + 1)
}

if (finish) {
this.info("排序完成!")
break
}
}
}

源碼我沒有上傳,剩下的源碼基本上都是原生的操作 DOM,沒什麼好看的。

效果截圖:

匿名用戶(答案刪除了)提到的把每一步過程信息記錄到一個數組,然後回放這個數組也是可行的方案。


你們這些程序員,不要總是想搞個大新聞。三十行原生能解決的事情,非要引入這庫那庫 ES678,搞個成千上萬行代碼,Excited!我是見得多了,前端哪個類庫我沒用過?Github 上的明哥,比你們高到不知道哪裡去了,我跟他談笑風生!別人造的輪子,你再拿來用一遍,你等於……你也有責任吧?

& #field{width:500px;height:510px;background:black;position:relative}
.bar{position:absolute;bottom:0;background:orange;border:1px solid brown;width:48px}
&

&
&& && && && && && && && && && &

&
!function(d){

var bars = [].slice.call(d.querySelectorAll(".bar"));
var arr = [8, 10, 3, 5, 6, 9, 2, 4, 7, 1];
var state = [];

var draw = function(){
var bar, s;
s = state.shift() || [];
for(bar in bars){
bars[bar].style.height = 50 * s[bar];
bars[bar].style.left = 50 * bar;
}
}

var sort = function(arr){
for(var i = 0; i &< arr.length; i++){ for(var j = 0; j &< arr.length - i - 1; j++){ if(arr[j] &> arr[j+1]){
arr[j] = arr[j] + arr[j+1];
arr[j+1] = arr[j] - arr[j+1];
arr[j] = arr[j] - arr[j+1];
state.push(JSON.parse(JSON.stringify(arr)));
}
}
}
}

sort(arr);
setInterval(draw, 500);

}(document)
&

預覽:RunJS


VisuAlgo - Sorting (Bubble, Selection, Insertion, Merge, Quick, Counting, Radix)


維護一個數組,在排序的每一步結束後,將當前狀態壓入數組。當整個排序過程結束後,你就得到了一個存儲了排序過程中所有狀態的數組。然後再按照數組的順序,依次繪製每一個狀態。


http://static.ricterz.me/kp.html

非前端代碼渣勿噴…

---

裡面實現了快速排序/選擇排序/冒泡排序的可視化…思路…看代碼最明確了吧…

好懷念寫代碼的時光啊233


好多年前, @趙劼 的windjs 庫中就有這樣的demo, 還有相關的ppt的

ppt 在這裡 上周末Jscex項目介紹的幻燈片

使用Jscex實現排序演算法動畫


用了 @Vkki 代碼里的(記錄狀態)思想,d3.js實現了繪圖,添加了點效果(條狀圖上顯示數字、加亮顯示交換元素、加亮顯示排序好的元素):

https://github.com/mikemelon/SortVisualization


謝邀。

VisuAlgo 是很牛逼的一個項目,不過很可惜它是不可商用的,我們不會像某些公司那樣不顧別人的聲明直接厚顏無恥地剽竊的 。

我們自己開發了一個。

這是我們數據結構課中使用的圖形化教學模塊,這課演示的是冒泡排序:

至於怎麼實現,我並不能說太多,我只能說我們用了 D3.js。


TL;DR: 在線例子及代碼 - Plunker

我來講一下要解決的幾個問題和 tips。


如何實現「交換」的動畫

我覺得這個是整個應用的難點。

看了 visual.net),他的實現是利用 CSS3 的 transform 函數裡面的 translate。這似乎是不錯的想法,但是我發現要用 JS 獲取 translate 對應的值的話,有點麻煩。

接著,我又看了一個答案的實現。他的方法是利用 CSS 中的 left。而 left 的值是相對於設定了 position: relative 的 parent

我不是很懂上面的方法。但是我想到了另一個方法:left 是相對於他本身。也就是設置他本身為 position: relative 而不是他的 parent

.bar {
position: relative;
left: 0; /* must set, or not transition when value in falsy */
/*transition: left 1s;*/
}

我之所以設置 left 為 0,是因為我們要用 CSS3 的 transition 實現漸變的效果。

然後,每次交換的時候,我們只需要把他當前的 left 加/減 柱形圖的寬度。沒錯,這就是這種方法的「缺點」之一,我們需要用 JS 寫死柱形圖的寬度。

swap () {
// ...

const getLeft = item =&>
parseInt(item.style.left.slice(0, -2)) || 0 // rm "px"

item1.style.left = `${this.barWidth + getLeft(item1)}px`
item2.style.left = `${-this.barWidth + getLeft(item2)}px`
}

在交換的時候,我們要先找到對應的 DOM 元素,也就是上面代碼中的 item 和 item2。

怎麼找?(假設我們排序的是一堆數字)

一開始我想到了兩種方法。

第一種是,根據數字,找到具有對用數字的 DOM 元素,就像這樣:

swap (value1, value2) {
const item1 = this.el.querySelector(`[data-value="${value1}"]`)
}

但這種方法是行不通的。為什麼?

因為當有多個數字相同的時候,我們找到的 DOM 元素不一定是我們想要交換的。因為 querySelector 返回的總是第一個匹配的元素。

那我們在 item1 後面才開始找 item2 行不行?使用 CSS3 的 ~ 選擇器。比如這樣:

swap (value1, value2) {
const item1 = this.el.querySelector(`[data-value="${value1}"]`)
const item2 = this.el.querySelector(`[data-value="${value2}"] ~ data-value="${value2}"]`)
}

這種方法有時可以,有時是不可以的。為什麼?

因為我們的 DOM 結構根本就沒有變化,只是用 CSS 的 left 在視覺上改變了位置而已。

因此,我們的第二種方法當然就是在交換的時候,不僅改變 left 的值,而且交換 DOM 的位置。

function swapDOM(element1, element2) {
element1.parentNode.insertBefore(element2, element1);
}

但是,這種方法還是行不通的。因為 insertBefore 會把 element2 從 DOM 中刪掉。這樣的話,就沒有了「交換」的漸變效果。

果然,我們還是不能 DOM 元素。那麼只能返回第一種方法。

這個時候我突然想到了 React 中循環的時候需要寫上 key 屬性。然後。。。然後只要把 key 和 數字綁定在一起,查找數字對應的 DOM 元素只需要使用 key 就行。

// data = [64, 39, 78, 36]
this.items = data.map((d, i) =&> ({key: `key-${i}`, value: d}))

swap (key1, key2) {
const item1 = this.el.querySelector(`[data-key="${key1}"]`)
}

終於搞定了「交換」動畫了,不知道有沒有更好的實現方法呢?


為什麼我的「交換」動畫一瞬間就跑完了

假設我們的排序演算法是這樣的:

sort () {
const items = this.items

for (let i = 0; i &< items.length; i++) { for (let j = 0; j &< items.length - i - 1; j++) { const item1 = items[j] const item2 = items[j + 1] if (less(item2.value, item1.value)) { swap(j, j + 1, items) } } } return this.items }

注意到,我們的 swap 函數是在 for 循環裡面調用的,這是沒錯的。

然而我們的「交換」動畫就跑完了,根本沒有漸變的效果,我們想要的是等到前一個交換動畫完成後,下一個才發生。為什麼會這樣?因為我們的兩個 for 是瞬間就可以跑完的= =

怎麼解決這個問題呢?setInterval?好像會把排序演算法的邏輯擾亂。

突然,我想到了 jQuery 好像有個動畫隊列的東西。

也就是說,我們可以把所有的動畫先放在一個隊列裡面。然後再一個一個地出隊,一個一個地調用。

for () {
for () {
if (less(item2.value, item1.value)) {
this.queue.push(() =&> this.swap(item1.key, item2.key))
}
}
}

play () {
const intervalId = setInterval(() =&> {
if (this.queue.length === 0) {
clearInterval(intervalId)
} else {
const swap = this.queue.shift()
swap()
}
}, 2 * 1000)
}

看了知乎上的答案,這個問題還有其他實現的方法。總的來說,就是如何解決非同步編程問題。


Tips

可以利用 CSS 的 偽元素::before 以及 attr 函數,來實現柱形圖上顯示對應的數字。

.bar::before {
content: attr(data-value);
position: absolute;
top: -16px;
color: #233;
}


Continue

我們的代碼還可以繼續優化,比如介面如何設計,使得可以擴展於其他的排序演算法。還有用戶體驗,比如,排序前中後狀態的顏色都設為不同,等等。

--------- 來自我的 blog


實現了一下冒泡排序、插入排序、選擇排序、快速排序、歸併排序、希爾排序的動畫演示。

對於保存每一步的狀態試過3種方法。

1.讓JS暫停。 減慢循環速度。 實現起來會有問題。

2.使用閉包+setTimeout()。 代碼量多,不方便修改。難以實現排序速度加快或減慢。

3.循環中保存排序狀態。再使用setInterval()。

最後使用的第三種。

另外有些排序如果要做動畫的話可能需要重寫排序的邏輯。

比如我開始寫的快速排序。使用的個簡單的遞歸,不是在同一個數組上進行的操作。就比較難得到數組當前的排序狀態。

後來在遞歸上加入了起止位。在原數組上進行操作。就可以獲取到整個數組的狀態了。

github:GitHub - liusaint/sortAnimation: JavaScript動畫展示常見排序演算法


Web 前端開發需要使用 MVVM 框架嗎? - 知乎用戶的回答

冒泡排序演算法的可視化


我在兩年前寫過 為了面試。。。

當時寫的 回頭看看代碼 感覺好一般 不過為了面試 源碼啥的 都沒有壓縮

效果如圖

地址為 排序演算法動畫特效

右鍵查看源代碼


繪圖用的是Canvas,數字越小高度越低、顏色越深。大概就是這樣~很早之前寫的了,包括冒泡、插入和選擇三種n2的排序方法。

http://app.dingdewen.com/algorithm/sort/

這幾種排序實質上都是兩重循環,把每一次交換的數對和產生的新序列push到一個數組裡,排序完成之後再用setInterval一步步呈現出來。

排列和繪製是完全分開的,方便擴展任意排序演算法。


在線演示地址 可視化排序 by sean熊

我的思路是這樣,不改變原有演算法,收集演算法對數組的改動過程到隊列,然後用定時器展示具體過程

下面是核心代碼:

&
&