ソートアルゴリズムを映像化してみた norahiko Follow 2011-04-13 03:49:59 License: MIT License Fork41 Fav95 View120634 よくあるやつです。ぼんやり眺めてると、とても癒されます。 今のところ確認してる不具合は、 ・Operaでは、要素を101以上に増やすと全く表示されなくなる。 ・Webkitだと、グラフの右端にスペースができる。 ・IE8だとエラーが出て全く動かず。 <- 直しました Play Stop Reload Fullscreen Smart Phone Fork tree Readme JavaScript 364 lines HTML 312 lines CSS 61 lines よくあるやつです。ぼんやり眺めてると、とても癒されます。 今のところ確認してる不具合は、 ・Operaでは、要素を101以上に増やすと全く表示されなくなる。 ・Webkitだと、グラフの右端にスペースができる。 ・IE8だとエラーが出て全く動かず。 <- 直しました ソートアルゴリズムを映像化してみた classy-1.4.js (function(){ var PROFILE = false //var PROFILE = true // ----------------------------------------- // Utils // ----------------------------------------- jQuery.fn.swap = function(b){ b = jQuery(b)[0]; var a = this[0]; var temp = a.parentNode.insertBefore(document.createTextNode(''), a); b.parentNode.insertBefore(a, b); temp.parentNode.insertBefore(b, temp); temp.parentNode.removeChild(temp); return this; } Array.prototype.insert = function(value, index){ var array = this for(var i = array.length - 1; index <= i; i--){ array[i + 1] = array[i] } array[index] = value } Array.prototype.insertBefore = function(from, to){ this.insert(this[from], to) if(to < from){ from += 1 } this.splice(from, 1) } Array.prototype.swap = function(a, b){ var temp = this[a] this[a] = this[b] this[b] = temp } function range(min, max){ var array = [] while(min < max){ array.push(min) min++ } return array } function randrange(min, max){ return Math.floor(Math.random() * (max - min)) + min } function shuffle(array){ var length = array.length for(var i = 0; i < length; i++){ var j = randrange(0, length) var temp = array[i] array[i] = array[j] array[j] = temp } return array } window.profile = { nowProfiling: false, start: function(name){ if(PROFILE === false) return if(this.nowProfiling){ console.profileEnd() } this.nowProfiling = true console.profile(name) }, end: function(){ if(PROFILE === false) return this.nowProfiling = false console.profileEnd() } } // ----------------------------------------- // Queue class // ----------------------------------------- var Queue = Class.$extend({ __init__: function(){ this.length = 0 this.i = 0 this.queue = [] }, get: function(){ if(this.length === 0) return undefined this.length-- return this.queue[this.i++] }, put: function(value){ this.queue.push(value) this.length++ } }) // ----------------------------------------- // Controller class // ----------------------------------------- Controller = Class.$extend({ widget: $("<span class='widget'></span>"), reset: $.noop, onSpeedChange: $.noop, onLengthChange: $.noop, __init__: function(defaults){ this.element = $("<div class='controller'>") var restart = this._createRestartButton() var buttonset = this._createLengthButtonSet(defaults.length) var slider = this._createSpeedSlider(defaults.speed) this.element.append(restart).append(buttonset).append(slider) }, _createRestartButton: function(){ var self = this var button = $("<button>Restart</button>").button().click(function(){ self.restart() }) return this.widget.clone().append(button) }, _createSpeedSlider: function(defaultSpeed){ var self = this var amount = $("<span class='speed-amount'></span>").text(defaultSpeed) var slider = $("<span class='speed-slider'></span>") slider.slider({ min: 1, max: 300, value: defaultSpeed, slide: function(event, ui){ amount.text(ui.value) self.onSpeedChange(ui.value) } }) var sliderWrapper = $("<span>").append(amount).append(slider) return this.widget.clone().text("Speed: ").append(sliderWrapper) }, _createLengthButtonSet: function(defaultLength){ var self = this var buttonset = this.widget.clone().addClass("length-button") var radioName = "graphical-sort-radio" var _label = $("<label>") var _radio = $("<input type='radio'>").attr("name", radioName) $.each([5, 10, 30, 50, 100, 200], function(i, length){ var label = _label.clone().text(length).attr("for", radioName + length) var radio = _radio.clone().attr("id", radioName + length).val(length) buttonset.append(label).append(radio) }) buttonset.find("input[value=" + defaultLength + "]").attr("checked", "checked") buttonset.buttonset() buttonset.click(function(event, ui){ self.onLengthChange(parseInt(event.target.value)) }) return buttonset } }) // ----------------------------------------- // Bar class // ----------------------------------------- var Bar = Class.$extend({ __init__: function(value){ this.value = value }, createElement: function(){ var bar = $("<span>") return bar } }) // ----------------------------------------- // Bars class // ----------------------------------------- var Bars = Class.$extend({ __init__: function(length, container){ this.length = length this.container = container this.bars = [] var values = this.values = shuffle(range(1, length+1)) for(var i = 0; i < length; i++){ this.bars[i] = Bar(values[i]) } this.elements = this._createElements() }, swap: function(a, b, command){ var className = "highlight" var elements = this.container.find("span") elements.removeClass(className) var barA = elements.eq(a) var barB = elements.eq(b) barA[0].className = barB[0].className = className if(command === C.swap){ barB.swap(barA) } }, insert: function(from, to){ var elements = this.container.find("span").removeClass("highlight") this.container[0].insertBefore(elements.eq(from).addClass("highlight")[0], elements[to]) }, _createElements: function(){ var elements = $() var length = this.length $.each(this.bars, function(){ var bar = this var element = bar.createElement() element.css("width", 100 / length + "%") element.css("height", bar.value / length * 100 + "%") elements = elements.add(element) }) return elements } }) var Command = Class.$extend({ __classvars__: { highlight: "highlight", swap: "swap", insert: "insert", set: "set" } }) var C = Command // ----------------------------------------- // GraphicalSort class // ----------------------------------------- GraphicalSort = Class.$extend({ length: 30, // default list length speed: 100, // default speed currentTaskId: -1, __init__: function(){}, // graphical API compare: function(a, b){ var command = C.highlight if(this.values[a] > this.values[b]){ this.values.swap(a, b) command = C.swap } this.task.put([a, b, command]) }, // graphical API highlight: function(a, b){ this.task.put([a, b, C.highlight]) }, // graphical API swap: function(a, b){ this.values.swap( a, b) this.task.put([a, b, C.swap]) }, // graphical API insertBefore: function(from, to){ this.values.insertBefore(from, to) this.task.put([from, to, C.insert]) }, show: function(viewElement){ if(this.sortFunc === undefined){ throw Error("sort function is undefined") } this.$sort = $("<div class='graphical-sort'>") this.$sort.append(this._createController().element) this.container = $("<div class='bars-container'>") this.$sort.append(this.container) viewElement.append(this.$sort) this.displayBars() }, displayBars: function(){ clearTimeout(this.currentTaskId) this.bars = Bars(this.length, this.container) this.values = this.bars.values this.container.empty().append(this.bars.elements) this._initTask() profile.start() this._setTimeout() }, complete: function(){ this.container.find("span").removeClass("highlight") if(this.sortFunc.name === "bogoSort"){ if(this.bogoSortCompleted === false){ this._initTask() this._setTimeout() return } } profile.end() }, _createController: function(){ this.controller = Controller({ speed: this.speed, length: this.length }) return this._setEventToController(this.controller) }, _setEventToController: function(controller){ var self = this controller.onLengthChange = function(length){ self.length = length self.displayBars() } controller.onSpeedChange = function(speed){ self.speed = speed } controller.restart = function(){ self.displayBars() } return controller }, _initTask: function(){ this.task = Queue() this.sortFunc() }, _next: function(){ var order = this.task.get() if(order === undefined){ this.complete() return } var command = order[2] if(command === C.insert){ this.bars.insert(order[0], order[1]) }else{ this.bars.swap(order[0], order[1], command) } this._setTimeout() }, _setTimeout: function(){ var self = this var interval = 2000 / this.speed this.currentTaskId = setTimeout(function(){ self._next() }, interval) } }) })() <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script> <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/themes/cupertino/jquery-ui.css" rel="stylesheet"> <div id="view"> </div> <script> $(function(){ // ----------------------------------------- // Bubble sort // ----------------------------------------- function bubbleSort(){ var array = this.values var length = array.length for(var i = length - 1; 0 < i; i--){ for(var j = 0; j < i; j++){ this.compare(j, j + 1) } } } // ----------------------------------------- // Selection sort // ----------------------------------------- function selectionSort(){ var array = this.values var length = array.length for(var i = 0; i < length - 1; i++){ var minIndex = i var minValue = array[minIndex] for (var j = i + 1; j < length; j++) { this.highlight(j, minIndex) if (array[j] < minValue) { minIndex = j minValue = array[minIndex] } } this.compare(i, minIndex) } return array } // ----------------------------------------- // Shaker Sort // ----------------------------------------- function shakerSort(){ var array = this.values var length = array.length var left = 0 var right = length - 1 var lastSwappedLeft = left var lastSwappedRight = right while(left < right){ lastSwappedRight = 0 for(var i = left; i < right; i++){ if(array[i] > array[i + 1]){ this.swap(i, i + 1) lastSwappedRight = i }else{ this.highlight(i, i + 1) } } right = lastSwappedRight lastSwappedLeft = length - 1 for(var j = right; left < j; j--){ if(array[j - 1] > array[j]){ this.swap(j - 1, j) lastSwappedLeft = j }else{ this.highlight(j - 1, j) } } left = lastSwappedLeft } } // ----------------------------------------- // Insertion sort // ----------------------------------------- function insertionSort(){ var array = this.values var length = array.length for(var i = 1; i < length; i++){ for(var j = i; 0 < j; j--){ if(array[j - 1] > array[j]){ this.swap(j - 1, j) }else{ this.highlight(j - 1, j) break } } } } // ----------------------------------------- // Shell Sort // ----------------------------------------- function shellSort(){ var array = this.values var length = array.length var gap = 1 while(gap < length) { gap = 3 * gap + 1 } while(gap > 1){ gap = Math.floor(gap / 3) for(var i = gap; i < length; i++){ for(var j = i; 0 < j; j -= gap){ if(array[j - gap] > array[j]){ this.swap(j - gap, j) }else{ this.highlight(j - gap, j) break } } } } } // ----------------------------------------- // Quick sort // ----------------------------------------- function quickSort(first, last){ // TODO: あとで書き直す var array = this.values first = (first === undefined) ? 0 : first last = (last === undefined) ? (array.length - 1) : last var pivotIndex = Math.floor((first + last) / 2) var pivotValue = array[pivotIndex] var f = first, l = last while(true){ while(true){ this.highlight(f, pivotIndex) if(!(array[f] < pivotValue)) break f++ } while(true){ this.highlight(l, pivotIndex) if(!(pivotValue < array[l])) break l-- } if(l <= f){ break } if(pivotIndex === l){ pivotIndex = f } if(pivotIndex === l){ pivotIndex = l } this.compare(f, l) f++; l-- } if(first < f - 1) quickSort.call(this, first, f - 1) if(l + 1 < last) quickSort.call(this, l + 1, last) } // ----------------------------------------- // Merge sort // ----------------------------------------- function mergeSort(first, last){ var array = this.values first = (first === undefined) ? 0 : first last = (last === undefined) ? array.length - 1 : last if (last - first < 1) { return } var middle = Math.floor((first + last) / 2) mergeSort.call(this, first, middle) mergeSort.call(this, middle + 1, last) var f = first var m = middle while (f <= m && m + 1 <= last) { this.highlight(f, m + 1) if (array[f] >= array[m + 1]) { this.insertBefore(m + 1, f) m++ } f++ } } // ----------------------------------------- // Heap sort // ----------------------------------------- function swapUp(array, current){ var parent = Math.floor((current - 1) / 2) while(current != 0){ if (!(array[current] > array[parent])) { this.highlight(current, parent) break } this.swap(current, parent) current = parent parent = Math.floor((current - 1) / 2) } } function swapDown(array, current, length){ var child = current * 2 + 1 while(true){ if(array[child] < array[child + 1]){ child += 1 } if(array[current] >= array[child]){ this.highlight(current, child) break } if(length <= child){ break } this.swap(current, child) current = child child = current * 2 + 1 } } function heapify(array){ for(var i = 0; i < array.length; i++){ swapUp.call(this, array, i) } } function heapSort(){ var array = this.values heapify.call(this, array) for(var i = array.length - 1; 0 < i; i--){ if(array[0] > array[i]){ this.swap(0, i) }else{ this.highlight(0, i) } swapDown.call(this, array, 0, i) } } // ----------------------------------------- // Bogo sort // ----------------------------------------- function bogoSort(){ var array = this.values this.bogoSortCompleted = false var length = array.length // shffle for(var i = 0; i < length; i++){ var j = Math.floor(Math.random() * length) this.swap(i, j) } // check for(var i = 0; i < length - 1; i++){ this.highlight(i, i + 1) if(array[i] > array[i + 1]){ return // incomplete } } this.bogoSortCompleted = true } bogoSort.name = "bogoSort" // ----------------------------------------- // Main // ----------------------------------------- var sort = GraphicalSort() // default sort function sort.sortFunc = bubbleSort var view = $("#view") view.width($(window).width()).height($(window).height() - 125) sort.show(view) // ----------------------------------------- // Sort menu // ----------------------------------------- var sortMenu = { "Bubble": bubbleSort, "Selection": selectionSort, "Shaker": shakerSort, "Insertion": insertionSort, "Shell": shellSort, "Quick": quickSort, "Merge": mergeSort, "Heap": heapSort, "Bogo": bogoSort } var menu = $("<div>").insertBefore(view).css({ height: 65, margin: "10px 0px", fontSize: 12 }) $.each(sortMenu, function(name, func){ var radio = $("<input type='radio' name='sort-menu' >").attr("id", name).appendTo(menu) var label = $("<label>").attr("for", name).text(name).appendTo(menu) radio.click(function(){ sort.sortFunc = func sort.displayBars() }) if(sort.sortFunc === func){ radio.attr("checked", "true") } }) menu.buttonset() }) </script> ソートアルゴリズムを映像化してみた html5doctor.com Reset Stylesheet html, body{ padding: 0px; margin: 0px; background: #333; color: white; font-weight: bold; } .graphical-sort{ position: relative; width: 100%; height: 100%; padding-top: 40px; } .graphical-sort .bars-container{ height: 100%; white-space: nowrap; overflow: hidden; } .graphical-sort .bars-container span{ display: inline-block; position: relative; height: 100%; background: #75c0ee; border-left: 1px solid #222; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .graphical-sort .bars-container span.highlight{ background: #aee496; } .graphical-sort .controller{ position: absolute; font-size: 10px; white-space: nowrap; overflow: visible; top: 0px; } .graphical-sort .controller .widget{ margin-right: 5px; } .graphical-sort .controller .speed-amount{ display: inline-block; width: 25px; } .graphical-sort .controller .speed-slider{ display: inline-block; width: 95px; } よくあるやつです。ぼんやり眺めてると、とても癒されます。 今のところ確認してる不具合は、 ・Operaでは、要素を101以上に増やすと全く表示されなくなる。 ・Webkitだと、グラフの右端にスペースができる。 ・IE8だとエラーが出て全く動かず。 <- 直しました (function(){ var PROFILE = false //var PROFILE = true // ----------------------------------------- // Utils // ----------------------------------------- jQuery.fn.swap = function(b){ b = jQuery(b)[0]; var a = this[0]; var temp = a.parentNode.insertBefore(document.createTextNode(''), a); b.parentNode.insertBefore(a, b); temp.parentNode.insertBefore(b, temp); temp.parentNode.removeChild(temp); return this; } Array.prototype.insert = function(value, index){ var array = this for(var i = array.length - 1; index <= i; i--){ array[i + 1] = array[i] } array[index] = value } Array.prototype.insertBefore = function(from, to){ this.insert(this[from], to) if(to < from){ from += 1 } this.splice(from, 1) } Array.prototype.swap = function(a, b){ var temp = this[a] this[a] = this[b] this[b] = temp } function range(min, max){ var array = [] while(min < max){ array.push(min) min++ } return array } function randrange(min, max){ return Math.floor(Math.random() * (max - min)) + min } function shuffle(array){ var length = array.length for(var i = 0; i < length; i++){ var j = randrange(0, length) var temp = array[i] array[i] = array[j] array[j] = temp } return array } window.profile = { nowProfiling: false, start: function(name){ if(PROFILE === false) return if(this.nowProfiling){ console.profileEnd() } this.nowProfiling = true console.profile(name) }, end: function(){ if(PROFILE === false) return this.nowProfiling = false console.profileEnd() } } // ----------------------------------------- // Queue class // ----------------------------------------- var Queue = Class.$extend({ __init__: function(){ this.length = 0 this.i = 0 this.queue = [] }, get: function(){ if(this.length === 0) return undefined this.length-- return this.queue[this.i++] }, put: function(value){ this.queue.push(value) this.length++ } }) // ----------------------------------------- // Controller class // ----------------------------------------- Controller = Class.$extend({ widget: $("<span class='widget'></span>"), reset: $.noop, onSpeedChange: $.noop, onLengthChange: $.noop, __init__: function(defaults){ this.element = $("<div class='controller'>") var restart = this._createRestartButton() var buttonset = this._createLengthButtonSet(defaults.length) var slider = this._createSpeedSlider(defaults.speed) this.element.append(restart).append(buttonset).append(slider) }, _createRestartButton: function(){ var self = this var button = $("<button>Restart</button>").button().click(function(){ self.restart() }) return this.widget.clone().append(button) }, _createSpeedSlider: function(defaultSpeed){ var self = this var amount = $("<span class='speed-amount'></span>").text(defaultSpeed) var slider = $("<span class='speed-slider'></span>") slider.slider({ min: 1, max: 300, value: defaultSpeed, slide: function(event, ui){ amount.text(ui.value) self.onSpeedChange(ui.value) } }) var sliderWrapper = $("<span>").append(amount).append(slider) return this.widget.clone().text("Speed: ").append(sliderWrapper) }, _createLengthButtonSet: function(defaultLength){ var self = this var buttonset = this.widget.clone().addClass("length-button") var radioName = "graphical-sort-radio" var _label = $("<label>") var _radio = $("<input type='radio'>").attr("name", radioName) $.each([5, 10, 30, 50, 100, 200], function(i, length){ var label = _label.clone().text(length).attr("for", radioName + length) var radio = _radio.clone().attr("id", radioName + length).val(length) buttonset.append(label).append(radio) }) buttonset.find("input[value=" + defaultLength + "]").attr("checked", "checked") buttonset.buttonset() buttonset.click(function(event, ui){ self.onLengthChange(parseInt(event.target.value)) }) return buttonset } }) // ----------------------------------------- // Bar class // ----------------------------------------- var Bar = Class.$extend({ __init__: function(value){ this.value = value }, createElement: function(){ var bar = $("<span>") return bar } }) // ----------------------------------------- // Bars class // ----------------------------------------- var Bars = Class.$extend({ __init__: function(length, container){ this.length = length this.container = container this.bars = [] var values = this.values = shuffle(range(1, length+1)) for(var i = 0; i < length; i++){ this.bars[i] = Bar(values[i]) } this.elements = this._createElements() }, swap: function(a, b, command){ var className = "highlight" var elements = this.container.find("span") elements.removeClass(className) var barA = elements.eq(a) var barB = elements.eq(b) barA[0].className = barB[0].className = className if(command === C.swap){ barB.swap(barA) } }, insert: function(from, to){ var elements = this.container.find("span").removeClass("highlight") this.container[0].insertBefore(elements.eq(from).addClass("highlight")[0], elements[to]) }, _createElements: function(){ var elements = $() var length = this.length $.each(this.bars, function(){ var bar = this var element = bar.createElement() element.css("width", 100 / length + "%") element.css("height", bar.value / length * 100 + "%") elements = elements.add(element) }) return elements } }) var Command = Class.$extend({ __classvars__: { highlight: "highlight", swap: "swap", insert: "insert", set: "set" } }) var C = Command // ----------------------------------------- // GraphicalSort class // ----------------------------------------- GraphicalSort = Class.$extend({ length: 30, // default list length speed: 100, // default speed currentTaskId: -1, __init__: function(){}, // graphical API compare: function(a, b){ var command = C.highlight if(this.values[a] > this.values[b]){ this.values.swap(a, b) command = C.swap } this.task.put([a, b, command]) }, // graphical API highlight: function(a, b){ this.task.put([a, b, C.highlight]) }, // graphical API swap: function(a, b){ this.values.swap( a, b) this.task.put([a, b, C.swap]) }, // graphical API insertBefore: function(from, to){ this.values.insertBefore(from, to) this.task.put([from, to, C.insert]) }, show: function(viewElement){ if(this.sortFunc === undefined){ throw Error("sort function is undefined") } this.$sort = $("<div class='graphical-sort'>") this.$sort.append(this._createController().element) this.container = $("<div class='bars-container'>") this.$sort.append(this.container) viewElement.append(this.$sort) this.displayBars() }, displayBars: function(){ clearTimeout(this.currentTaskId) this.bars = Bars(this.length, this.container) this.values = this.bars.values this.container.empty().append(this.bars.elements) this._initTask() profile.start() this._setTimeout() }, complete: function(){ this.container.find("span").removeClass("highlight") if(this.sortFunc.name === "bogoSort"){ if(this.bogoSortCompleted === false){ this._initTask() this._setTimeout() return } } profile.end() }, _createController: function(){ this.controller = Controller({ speed: this.speed, length: this.length }) return this._setEventToController(this.controller) }, _setEventToController: function(controller){ var self = this controller.onLengthChange = function(length){ self.length = length self.displayBars() } controller.onSpeedChange = function(speed){ self.speed = speed } controller.restart = function(){ self.displayBars() } return controller }, _initTask: function(){ this.task = Queue() this.sortFunc() }, _next: function(){ var order = this.task.get() if(order === undefined){ this.complete() return } var command = order[2] if(command === C.insert){ this.bars.insert(order[0], order[1]) }else{ this.bars.swap(order[0], order[1], command) } this._setTimeout() }, _setTimeout: function(){ var self = this var interval = 2000 / this.speed this.currentTaskId = setTimeout(function(){ self._next() }, interval) } }) })() <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script> <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/themes/cupertino/jquery-ui.css" rel="stylesheet"> <div id="view"> </div> <script> $(function(){ // ----------------------------------------- // Bubble sort // ----------------------------------------- function bubbleSort(){ var array = this.values var length = array.length for(var i = length - 1; 0 < i; i--){ for(var j = 0; j < i; j++){ this.compare(j, j + 1) } } } // ----------------------------------------- // Selection sort // ----------------------------------------- function selectionSort(){ var array = this.values var length = array.length for(var i = 0; i < length - 1; i++){ var minIndex = i var minValue = array[minIndex] for (var j = i + 1; j < length; j++) { this.highlight(j, minIndex) if (array[j] < minValue) { minIndex = j minValue = array[minIndex] } } this.compare(i, minIndex) } return array } // ----------------------------------------- // Shaker Sort // ----------------------------------------- function shakerSort(){ var array = this.values var length = array.length var left = 0 var right = length - 1 var lastSwappedLeft = left var lastSwappedRight = right while(left < right){ lastSwappedRight = 0 for(var i = left; i < right; i++){ if(array[i] > array[i + 1]){ this.swap(i, i + 1) lastSwappedRight = i }else{ this.highlight(i, i + 1) } } right = lastSwappedRight lastSwappedLeft = length - 1 for(var j = right; left < j; j--){ if(array[j - 1] > array[j]){ this.swap(j - 1, j) lastSwappedLeft = j }else{ this.highlight(j - 1, j) } } left = lastSwappedLeft } } // ----------------------------------------- // Insertion sort // ----------------------------------------- function insertionSort(){ var array = this.values var length = array.length for(var i = 1; i < length; i++){ for(var j = i; 0 < j; j--){ if(array[j - 1] > array[j]){ this.swap(j - 1, j) }else{ this.highlight(j - 1, j) break } } } } // ----------------------------------------- // Shell Sort // ----------------------------------------- function shellSort(){ var array = this.values var length = array.length var gap = 1 while(gap < length) { gap = 3 * gap + 1 } while(gap > 1){ gap = Math.floor(gap / 3) for(var i = gap; i < length; i++){ for(var j = i; 0 < j; j -= gap){ if(array[j - gap] > array[j]){ this.swap(j - gap, j) }else{ this.highlight(j - gap, j) break } } } } } // ----------------------------------------- // Quick sort // ----------------------------------------- function quickSort(first, last){ // TODO: あとで書き直す var array = this.values first = (first === undefined) ? 0 : first last = (last === undefined) ? (array.length - 1) : last var pivotIndex = Math.floor((first + last) / 2) var pivotValue = array[pivotIndex] var f = first, l = last while(true){ while(true){ this.highlight(f, pivotIndex) if(!(array[f] < pivotValue)) break f++ } while(true){ this.highlight(l, pivotIndex) if(!(pivotValue < array[l])) break l-- } if(l <= f){ break } if(pivotIndex === l){ pivotIndex = f } if(pivotIndex === l){ pivotIndex = l } this.compare(f, l) f++; l-- } if(first < f - 1) quickSort.call(this, first, f - 1) if(l + 1 < last) quickSort.call(this, l + 1, last) } // ----------------------------------------- // Merge sort // ----------------------------------------- function mergeSort(first, last){ var array = this.values first = (first === undefined) ? 0 : first last = (last === undefined) ? array.length - 1 : last if (last - first < 1) { return } var middle = Math.floor((first + last) / 2) mergeSort.call(this, first, middle) mergeSort.call(this, middle + 1, last) var f = first var m = middle while (f <= m && m + 1 <= last) { this.highlight(f, m + 1) if (array[f] >= array[m + 1]) { this.insertBefore(m + 1, f) m++ } f++ } } // ----------------------------------------- // Heap sort // ----------------------------------------- function swapUp(array, current){ var parent = Math.floor((current - 1) / 2) while(current != 0){ if (!(array[current] > array[parent])) { this.highlight(current, parent) break } this.swap(current, parent) current = parent parent = Math.floor((current - 1) / 2) } } function swapDown(array, current, length){ var child = current * 2 + 1 while(true){ if(array[child] < array[child + 1]){ child += 1 } if(array[current] >= array[child]){ this.highlight(current, child) break } if(length <= child){ break } this.swap(current, child) current = child child = current * 2 + 1 } } function heapify(array){ for(var i = 0; i < array.length; i++){ swapUp.call(this, array, i) } } function heapSort(){ var array = this.values heapify.call(this, array) for(var i = array.length - 1; 0 < i; i--){ if(array[0] > array[i]){ this.swap(0, i) }else{ this.highlight(0, i) } swapDown.call(this, array, 0, i) } } // ----------------------------------------- // Bogo sort // ----------------------------------------- function bogoSort(){ var array = this.values this.bogoSortCompleted = false var length = array.length // shffle for(var i = 0; i < length; i++){ var j = Math.floor(Math.random() * length) this.swap(i, j) } // check for(var i = 0; i < length - 1; i++){ this.highlight(i, i + 1) if(array[i] > array[i + 1]){ return // incomplete } } this.bogoSortCompleted = true } bogoSort.name = "bogoSort" // ----------------------------------------- // Main // ----------------------------------------- var sort = GraphicalSort() // default sort function sort.sortFunc = bubbleSort var view = $("#view") view.width($(window).width()).height($(window).height() - 125) sort.show(view) // ----------------------------------------- // Sort menu // ----------------------------------------- var sortMenu = { "Bubble": bubbleSort, "Selection": selectionSort, "Shaker": shakerSort, "Insertion": insertionSort, "Shell": shellSort, "Quick": quickSort, "Merge": mergeSort, "Heap": heapSort, "Bogo": bogoSort } var menu = $("<div>").insertBefore(view).css({ height: 65, margin: "10px 0px", fontSize: 12 }) $.each(sortMenu, function(name, func){ var radio = $("<input type='radio' name='sort-menu' >").attr("id", name).appendTo(menu) var label = $("<label>").attr("for", name).text(name).appendTo(menu) radio.click(function(){ sort.sortFunc = func sort.displayBars() }) if(sort.sortFunc === func){ radio.attr("checked", "true") } }) menu.buttonset() }) </script> html, body{ padding: 0px; margin: 0px; background: #333; color: white; font-weight: bold; } .graphical-sort{ position: relative; width: 100%; height: 100%; padding-top: 40px; } .graphical-sort .bars-container{ height: 100%; white-space: nowrap; overflow: hidden; } .graphical-sort .bars-container span{ display: inline-block; position: relative; height: 100%; background: #75c0ee; border-left: 1px solid #222; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .graphical-sort .bars-container span.highlight{ background: #aee496; } .graphical-sort .controller{ position: absolute; font-size: 10px; white-space: nowrap; overflow: visible; top: 0px; } .graphical-sort .controller .widget{ margin-right: 5px; } .graphical-sort .controller .speed-amount{ display: inline-block; width: 25px; } .graphical-sort .controller .speed-slider{ display: inline-block; width: 95px; } use an iframe compat browser, deer Tweet QR code Embed Design view Code view <script type="text/javascript" src="http://jsdo.it/blogparts/oxIy/js?view=design"></script><p class="ttlBpJsdoit" style="width: 465px; margin: 0; text-align: right; font-size: 11px;"><a href="http://jsdo.it/norahiko/oxIy" title="ソートアルゴリズムを映像化してみた">ソートアルゴリズムを映像化してみた - jsdo.it - share JavaScript, HTML5 and CSS</a></p> zip tags algorithm sort Tweet twitter Tags CS-Theory HTML5 algorithm application array art&design binary canvas graphics insertion jQuery javascript library&test search sort webkit アルゴリズム 癒し Favorite by satorupan suffocair wahooneko zenion Kenpi S.Falahati hika69 kyanny muvoiaia SorAmber valueshare ystream banzaimarch vault.vans siouxcitizen.. yksk shuhei happi_tan1 show555 asm xiuxing yoshimax snowsunny ww24 albert Gaia hdemon asakura takishiki dadachi ksk1015 ngtn kt9 susisu2413 hi4sandy soramugi jalbertbowde.. kuroarizuka nehahelo batadesu_ libero_18 shunito indigo13love.. sssinsi tsmallfield sonji07 tyru kyo_ago mumoshu piyotori edo_m18 kleinschmidt.. colspan tikamoton murakame yupasM U_E_D ethertank pypupypa chimanaco: algorithm dprize: CS-Theoryalgorithmarraybinaryinsertionsearchsearchsort rintarock: sortアルゴリズム na999ta: アルゴリズムjavascriptかっこいい!! dotimaging: アルゴリズム suparrow: アルゴリズム klovelovely: sort ynakajima: sortalgorithm Okaz: algorithmgraphicscanvas odiak: アルゴリズムjavascriptHTML5algorithmcanvas kbb_ya: アルゴリズム rintaro2039: アルゴリズムjQuerywebkit macoril: algorithmjavascriptsortwebkit e10lion: アルゴリズム TheSisb: sort amazingness ye117: sortアルゴリズムjQuery whitech0c0: アルゴリズムソートを視覚化できておもろい! nejires: アルゴリズム copimo: わかりやすい KappaTech: アルゴリズム癒しHTML5algorithmjQueryすごい…!見ていると癒される… swinging: algorithmcanvassort keiji.shimad..: アルゴリズム skoido: 癒しアルゴリズムいやし。。 udofukui: アルゴリズムsortalgorithm kabakiyo: アルゴリズム isimiya: アルゴリズム eiji: algorithm favac: sort algorithms kzh: CS-TheoryNice example of sorting algorithms. minikomi: 素晴らしい。redditにも乗せました~ paq: ボゴソートだと、まるでサウンドビジュアライザのようになる。 undo: ボゴソートわろた clockmaker: 最近jsdo.itが元気だなぁ ginpei: アルゴリズムまさかのボゴソートw 学校とかでこういうの見せてほしい。 kyutakna: sort解り易い!かな? sugyan: algorithmsort Forked sort new page view favorite forked forked: ソートアルゴリズムを映像化してみた satorupan 00 4views 365/312/61 algorithm sort forked: ソートアルゴリズムを映像化してみた prontoxzoan 00 11views 365/312/61 algorithm sort forked: ソートアルゴリズムを映像化してみた JohnLi 00 13views 365/312/61 algorithm sort forked: ソートアルゴリズムを映像化してみた streetjimmy 00 14views 365/312/61 algorithm sort 1 2 3 4 5 6 7 8 9 10NEXT>>