javascript实现的各种排序性能比较

<!DOCTYPE html>
<html sort-visualize-app>
	<head>
		<meta charset="UTF-8" />
		<title>javascript各种排序算法</title>
		<meta name="Description" content="jsdo.it - share JavaScript, HTML5 and CSS -" />
		<meta name="Keywords"  content="JavaScript,HTML5,CSS" />
		<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1" />
		<style type="text/css">
			body {
				background: #333;
				overflow: hidden;
			}
			.ui > div {
				display: inline-block;
				margin-bottom: 5px;
			}
			.ui input[type=radio] {
				display: none;
			}
			.ui .button-set {
				font-size: 0px;
				margin: 5px 5px;
			}
			.ui .button {
				display: inline-block;
				background: #ddd;
				padding: 6px 4px;
				border-right: 1px solid #bbb;
				font-size: 10px;
				font-family: monospace;
			}
			.ui .button:hover {
				background: #ccc;
			}
			.ui label:first-child .button {
				border-radius: 5px 0px 0px 5px;
			}
			.ui label:last-child .button {
				border-radius: 0px 5px 5px 0px;
				border-right-width: 0px;
			}
			.ui label:only-child .button {
				border-radius: 5px;
			}
			.ui input:checked + .button {
				background: #666;
				color: #fff;
			}
			.ui input[type=range] {
				position: relative;
				top: 7px;
			}
		</style>
		<meta charset="UTF-8">
		<title>Sort Visualize</title>
		<link rel="stylesheet" href="/norahiko/oxly/css" type="text/css" charset="utf-8">

	</head>
	<body>

		<div class="ui">
			<div data-bind="foreach: algorithmList" class="button-set">
				<label>
					<input type="radio" data-bind="checkedValue: $data, checked: $root.algorithm">
					<span data-bind="text: $data" class="button"></span> </label>
			</div>

			<div>
				<input type="range" data-bind="
				value: speed,
				attr: { min: speedMin, max: speedMax }">
			</div>

			<div data-bind="foreach: sizeList" class="button-set">
				<label>
					<input type="radio" data-bind="checkedValue: $data, checked: $root.size">
					<span data-bind="text: $data" class="button"></span> </label>
			</div>

			<div class="button-set">
				<label> <span data-bind="click: restart" class="button">Restart</span> </label>
			</div>
		</div>

		<div class="graph">
			<canvas id="graph-canvas" width="450" height="380"></canvas>
		</div>

		<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js" type="text/javascript" charset="utf-8"></script>
		<script src="/norahiko/oxly/js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			// https://github.com/norahiko/sort-visualize

			var helper = {
				range : function(min, max) {
					var res = [];
					for (var i = min; i < max; i++) {
						res.push(i);
					}
					return res;
				},

				shuffle : function(ary) {
					for (var i = ary.length - 1; 0 <= i; i--) {
						var rnd = Math.random() * (i + 1) | 0;
						helper.swap(ary, i, rnd);
					}
				},

				swap : function(ary, a, b) {
					if (a < 0 || b < 0 || ary.length <= a || ary.length <= b) {
						throw new Error('IndexError ' + a + " - " + b);
					}
					var temp = ary[a];
					ary[a] = ary[b];
					ary[b] = temp;
				},

				insert : function(ary, from, to) {
					while (from != to) {
						if (from < to) {
							helper.swap(ary, from, from + 1);
							from += 1;
						} else {
							helper.swap(ary, from, from - 1);
							from -= 1;
						}
					}
				},

				median3 : function(a, b, c) {
					if (b <= a)
						if (a <= c)
							return a;
						else if (c <= b)
							return b;
						else
							return c;
					else if (c <= a)
						return a;
					else if (c <= b)
						return c;
					else
						return b;
				},

				getCanvas : function(id) {
					var canvas = document.getElementById(id);
					if (canvas === null || canvas.nodeName.toLowerCase() !== 'canvas') {
						return document.createElement('canvas');
					}
					return canvas;
				}
			};

			var graph = {};

			(function() {
				var canvas;
				var ctx;
				var width;
				var height;

				var bgColor = '#333';
				var barColor = '#6cf';
				var highlightColor = '#cf6';

				graph.init = function(c) {
					canvas = c;
					ctx = canvas.getContext('2d');
					width = canvas.offsetWidth;
					height = canvas.offsetHeight;
				};

				graph.draw = function(highlightIndexes, values) {
					ctx.fillStyle = bgColor;
					ctx.fillRect(0, 0, width, height);
					var idx1 = highlightIndexes[0];
					var idx2 = highlightIndexes[1];

					var size = values.length;
					var barWidth = (width - size + 1) / size;
					var barHeightUnit = height / size;

					var x = 0;
					var h = 0;
					ctx.fillStyle = barColor;
					for (var i = 0; i < values.length; i++) {
						h = values[i] * barHeightUnit;
						if (i === idx1 || i === idx2) {
							ctx.fillStyle = highlightColor;
							ctx.fillRect(x, height - h, barWidth, h);
							ctx.fillStyle = barColor;
						} else {
							ctx.fillRect(x, height - h, barWidth, h);
						}
						x = x + barWidth + 1;
					}
				};
			})();

			function SortStep(type, indexes) {
				// type = 'swap' | 'highlight' | 'insert'
				this.type = type;
				this.indexes = indexes;
			}


			SortStep.SWAP = 'swap';
			SortStep.HIGHLIGHT = 'highlight';
			SortStep.INSERT = 'insert';

			SortStep.prototype.run = function(ary) {
				if (this.type === SortStep.SWAP) {
					helper.swap(ary, this.indexes[0], this.indexes[1]);
				} else if (this.type === SortStep.INSERT) {
					helper.insert(ary, this.indexes[0], this.indexes[1]);
					this.indexes[0] = -1;
				}
			};

			function SortAlgorithm(values) {
				this.values = values;
				this.size = values.length;
				this.steps = [];
				this.finished = false;
			}


			SortAlgorithm.prototype.sort = function(algorithm) {
				this[algorithm]();
				this.steps.reverse();
				if (algorithm !== 'bogo') {
					this.finished = true;
				}
			};

			SortAlgorithm.prototype.addStep = function(type, indexes) {
				this.steps.push(new SortStep(type, indexes));
			};

			SortAlgorithm.prototype.swap = function(a, b) {
				helper.swap(this.values, a, b);
				this.addStep(SortStep.SWAP, [a, b]);
			};

			SortAlgorithm.prototype.highlight = function(a, b) {
				this.addStep(SortStep.HIGHLIGHT, [a, b]);
			};

			SortAlgorithm.prototype.insert = function(from, to) {
				helper.insert(this.values, from, to);
				this.addStep(SortStep.INSERT, [from, to]);
			};

			SortAlgorithm.prototype.bubble = function bubbleSort() {
				for (var i = this.size - 1; 0 < i; i--) {
					for (var k = 0; k < i; k++) {
						if (this.values[k] > this.values[k + 1]) {
							this.swap(k, k + 1);
						} else {
							this.highlight(k, k + 1);
						}
					}
				}
			};

			SortAlgorithm.prototype.selection = function selectionSort() {
				for (var i = 0; i < this.size - 1; i++) {
					var min = i;
					for (var k = i + 1; k < this.size; k++) {
						this.highlight(min, k);
						if (this.values[k] < this.values[min]) {
							min = k;
						}
					}
					this.swap(i, min);
				}
			};

			SortAlgorithm.prototype.shaker = function shakerSort() {
				var left = 0;
				var right = this.size - 1;
				var incr = 1;
				var i = 0;
				var next;
				var lastSwapped = 0;

				var count = 0;
				while (left < right) {
					next = i + incr;
					if ((incr === 1 && this.values[i] > this.values[next]) || (incr === -1 && this.values[next] > this.values[i])) {
						this.swap(i, next);
						lastSwapped = i;
					} else {
						this.highlight(i, next);
					}

					if (next === right) {
						i = right = lastSwapped;
						incr = -incr;
					} else if (next === left) {
						i = left = lastSwapped;
						incr = -incr;
					} else {
						i = next;
					}
				}
			};

			SortAlgorithm.prototype.insertion = function insertionSort() {
				for (var i = 1; i < this.size; i++) {
					for (var k = i; 0 < k; k--) {
						if (this.values[k - 1] > this.values[k]) {
							this.swap(k - 1, k);
						} else {
							this.highlight(k - 1, k);
							break;
						}
					}
				}
			};

			SortAlgorithm.prototype.shell = function shellSort() {
				var gap = 1;
				while (gap < this.size) {
					gap = gap * 3 + 1;
				}

				while (1 < gap) {
					gap = gap / 3 | 0;
					for (var i = gap; i < this.size; i++) {
						for (var k = i; 0 < k; k -= gap) {
							if (this.values[k - gap] > this.values[k]) {
								this.swap(k - gap, k);
							} else {
								this.highlight(k - gap, k);
								break;
							}
						}
					}
				}
			};

			SortAlgorithm.prototype.merge = function mergeSort() {
				this.mergeSortImpl(0, this.size - 1);
			};

			SortAlgorithm.prototype.mergeSortImpl = function(left, right) {
				if (right <= left) {
					return;
				}
				var middle = (left + right) / 2 | 0;
				this.mergeSortImpl(left, middle);
				this.mergeSortImpl(middle + 1, right);

				var l = left;
				var m = middle + 1;
				while (l < m && m <= right) {
					this.highlight(l, m);
					if (this.values[l] >= this.values[m]) {
						this.insert(m, l);
						m++;
					}
					l++;
				}
			};

			SortAlgorithm.prototype.quick = function quickSort() {
				this.quickSortImpl(0, this.size - 1);
			};

			SortAlgorithm.prototype.quickSortImpl = function(left, right) {
				var values = this.values;
				var middle = (left + right) / 2 | 0;
				var pivot = helper.median3(values[left], values[middle], values[right]);
				var l = left;
				var r = right;
				while (true) {
					while (values[l] < pivot) {
						this.highlight(l, r);
						l++;
					}
					while (pivot < values[r]) {
						this.highlight(l, r);
						r--;
					}
					if (r <= l) {
						break;
					}
					this.swap(l, r);
					l++;
					r--;
				}

				if (left < l - 1) {
					this.quickSortImpl(left, l - 1);
				}
				if (r + 1 < right) {
					this.quickSortImpl(r + 1, right);
				}
			};

			SortAlgorithm.prototype.heap = function heapSort() {
				for (var i = 0; i < this.size; i++) {
					this.swapUp(i);
				}

				for ( i = this.size - 1; 0 < i; i--) {
					if (this.values[0] > this.values[i]) {
						this.swap(0, i);
					} else {
						this.highlight(0, i);
					}
					this.swapDown(0, i);
				}
			};

			SortAlgorithm.prototype.swapUp = function(cur) {
				var parent;
				while (cur !== 0) {
					parent = (cur - 1) / 2 | 0;
					if (this.values[parent] >= this.values[cur]) {
						this.highlight(parent, cur);
						break;
					}
					this.swap(parent, cur);
					cur = parent;
				}
			};

			SortAlgorithm.prototype.swapDown = function(cur, length) {
				var values = this.values;
				var child;
				while (true) {
					child = cur * 2 + 1;
					if (values[child] < values[child + 1]) {
						child += 1;
					}
					if (values[cur] >= values[child]) {
						this.highlight(cur, child);
						break;
					}
					if (length <= child) {
						break;
					}
					this.swap(cur, child);
					cur = child;
				}
			};

			SortAlgorithm.prototype.bogo = function bogoSort() {
				for (var i = 0; i < this.size; i++) {
					var rnd = (Math.random() * (this.size - i) | 0) + i;
					this.swap(i, rnd);
				}

				for ( i = 0; i < this.size - 1; i++) {
					this.highlight(i, i + 1);
					if (this.values[i] > this.values[i + 1]) {
						return;
					}
				}
				this.finished = true;
			};

			function ViewModel() {
				this.algorithm = ko.observable('Bubble');
				this.size = ko.observable(50);
				this.speed = ko.observable(9);

				this.sort = null;
				this.nums = [];
				this.algorithmList = ['Bubble', 'Selection', 'Shaker', 'Insertion', 'Shell', 'Merge', 'Heap', 'Quick', 'Bogo'];
				this.sizeList = [5, 10, 50, 100, 150];
				this.speedMin = 1;
				// 2 seconds
				this.speedMax = 22;
				// 4 milliseconds
				this.intervalId = -1;

				graph.init(helper.getCanvas('graph-canvas'));

				this.changed = ko.computed({
					read : function() {
						this.start(this.algorithm(), this.size());
					},
					owner : this,
					deferEvaluation : true,
				});
			}


			ViewModel.prototype.start = function(algorithm, size) {
				var vm = this;
				this.nums = helper.range(1, size + 1);
				helper.shuffle(this.nums);
				this.sort = new SortAlgorithm(this.nums.slice());

				clearInterval(this.intervalId);
				this.intervalId = setTimeout(animationFrame, 0);

				function animationFrame() {
					if (vm.sort.steps.length === 0) {
						if (vm.sort.finished) {
							graph.draw([-1, -1], vm.nums);
							return;
						} else {
							vm.sort.sort(algorithm.toLowerCase());
							console.log(vm.sort.steps.length);
						}
					}

					var step = vm.sort.steps.pop();
					step.run(vm.nums);
					graph.draw(step.indexes, vm.nums);
					vm.intervalId = setTimeout(animationFrame, vm.getIntervalTime());
				}

			};

			ViewModel.prototype.restart = function() {
				this.start(this.algorithm.peek(), this.size.peek());
			};

			ViewModel.prototype.getIntervalTime = function() {
				var speed = parseInt(this.speed.peek(), 10);
				return 2000 / speed / speed | 0;
			};

			if (document.documentElement.hasAttribute('sort-visualize-app')) {
				document.addEventListener('DOMContentLoaded', main);
			}

			function main() {
				var vm = window.vm = new ViewModel();
				ko.applyBindings(vm);
				vm.changed();
			}
		</script>
	</body>
</html>

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值