/**
* 常用排序总结
* 排序分类:插入排序、交换排序、选择排序和归并排序。
* Created by xj on 2017/3/8.
*/
// var array = [3,1,8,9,10,4,5,6,7,2];
var array = [0,10,20,8,25,35,6,18,30,5,15,28];
var compareTime = 0;
var changeTime = 0;
/**
* 冒牌排序
* 最简单的交换排序,严格意义上来说不算标准的冒泡排序,因为不满足“两两比较相邻记录”的条件。
* 思路:每一个关键字都和它后面的关键字比较,如果当前关键字不是最小的记录,则与相比较的关键
* 字交换位置,这样当前位置的关键字再一次循环后一定是最小值。
* 复杂度:本身有序就是n-1次比较;若正好倒序,则需要进行1+2+3+……+(n-1) = n(n-1)/2次比较,因为总的时间复杂度为O(n²)
*/
document.getElementById("show").innerHTML = array;
function sortBubble1() {
console.log("------交换排序------");
console.log("---" + array + "------");
for(var i = 0; i < this.array.length; i++)
{
for(var j = i; j < this.array.length; j++)
{
if(this.array[j] < this.array[i])
{
this.change(i, j);
}
compareTime ++;
}
console.log("---" + this.array + "---");
}
console.log(this.array + "\n compareTime = " + compareTime + "\n changeTime = " + changeTime);
}
/**
* 冒牌排序(正版)
* 真正的冒泡排序,每次循环从序列的末尾开始两两比较,若关键字(n-1)大于n,则交换位置,继续比较(n-2)和(n-1),
* 这样即保证每次循环第一个关键字都是最小值,而且序列后边的较小的关键字也会相对前移。
*/
function sortBubble2() {
console.log("------冒泡排序------");
console.log("---" + array + "------");
for(var i = 0; i < array.length; i++)
{
for(var j = array.length-2; j >= i; j--)
{
if(this.array[j] > this.array[j+1])
{
this.change(j, j+1);
}
compareTime ++;
}
console.log("---" + this.array + "---");
}
console.log(this.array + "\n compareTime = " + compareTime + "\n changeTime = " + changeTime);
}
/**
* 冒牌排序(改进版)
* 改进的冒泡排序,若存在当一定情况下,序列已经有序,没有必要进行重复的循环判断,减少冗余的比较次数。
*/
function sortBubble3() {
console.log("------冒泡排序改进------");
console.log("---" + array + "------");
var flag = true; //进入循环
for(var i = 0; i < array.length && flag; i++)
{
flag = false; //循环判断关键字置false,若此次循环中没有进行数据移动,则可以确定此时序列已经有序,无需再次进行比较和迁移
for(var j = array.length-2; j >= i; j--)
{
if(this.array[j] > this.array[j+1])
{
this.change(j, j+1);
flag = true; //若有数据移动,说明序列仍是无序,有必要再次进行循环
}
compareTime ++;
}
console.log("---" + this.array + "---");
}
console.log(this.array + "\n compareTime = " + compareTime + "\n changeTime = " + changeTime);
}
/**
* 简单选择排序
* 思想:通过n-1次关键字之间的比较,从n-1+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之。
* 优点:相对冒泡排序来说,交换移动数据的次数少了,这样就节约了相应的时间。
* 复杂度:比较次数一样多。对于交换次数而言,最好的时候交换0次,最差的时候交换n-1次。总的时间复杂度O(n²)
* 总结:尽管复杂度相同,但简单选择排序在性能上还是优于冒泡排序。
*/
function sortSelect() {
console.log("------简单选择排序------");
console.log("---" + array + "------");
var min = 0;
for(var i = 0; i < array.length; i++)
{
min = i;
for(var j = i; j < array.length; j++)
{
if(this.array[j] < this.array[min])
{
min = j;
}
compareTime ++;
}
if(min != i)
{
this.change(min, i);
}
console.log("---" + this.array + "---");
}
console.log(this.array + "\n compareTime = " + compareTime + "\n changeTime = " + changeTime);
}
/**
* 直接插入排序
*/
function sortInsert() {
console.log("------直接插入排序------");
console.log("---" + array + "------");
var temp = null;
var i,j = null;
for(i = 1; i < array.length; i++)
{
if(array[i] < array[i-1])
{
temp = array[i];
for(j = i-1; array[j] > temp; j--)
{
array[j+1] = array[j];
changeTime ++;
}
array[j+1] = temp;
}
compareTime ++;
console.log("---" + this.array + "---");
}
console.log(this.array + "\n compareTime = " + compareTime + "\n changeTime = " + changeTime);
}
/**
* 希尔排序
* 跳跃分隔策略:将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别就行插入排序后得到的结果是基本有序而不是局部有序。
* 算法复杂度:O(n³/²)
* 注意:非稳定排序
* 思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量
* 减至1时,整个文件恰被分成一组,算法便终止。
* 类别:插入排序
*/
function sortSheel() {
console.log("------希尔排序------");
console.log("---" + array + "------");
var temp = null;
var i,j = null;
// var increment = array.length;
var increment = 12
do
{
increment = parseInt(increment/3 + 1); //增序数列,此处最难理解。最优增量值有待商榷
for(i = increment; i < array.length; i++) //测试最好数据为dlta[k]=2E(t-k+1)-1(0<=k<=t<=㏒₂(n+1))
{
if(array[i] < array[i-increment]) //判断是否交换数据
{
temp = array[i]; //移动数据之前,先把要移动的数据存储在temp中
for(j = i-increment; j >= 0 && array[j] > temp; j-=increment) //此处循环继续进行的判断条件比较精髓,当j-=increment还能继续满足条件时
{ //要移动的数据array[j]跟temp比较大会继续移动
array[j+increment] = array[j]; //移动数据
compareTime ++;
changeTime ++;
}
array[j+increment] = temp; //上边循环内确定要移动的数据,这里确定最终交换的数据
}
compareTime ++;
}
console.log("---" + this.array + "---");
}
while (increment > 1);
console.log(this.array + "\n compareTime = " + compareTime + "\n changeTime = " + changeTime);
}
/**
* 堆排序:选择排序
* 思想:利用大顶堆进行排序的方法。将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是讲其与堆
* 堆数组末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中次大值。如此反复执行,便
* 能得到一个有序的序列了。
* 复杂度:O(n㏒n)
* 稳定:不稳定。
* 注意:出事构建堆排序所需要比较的次数较多,不适合排序序列个数很少的情况。
* @param i
*/
function sortHeap() {
console.log("------堆排序------");
console.log("---" + array + "------");
var length = array.length - 1; //此处为了将排序数组和js数组结合,只排序js数组下标>1的序列
for (var i = parseInt(length/2); i > 0; i--) //0-i表示有孩子的结点,从i开始递减。目的:把数组变成大顶堆
{
adjustHeap(i, length);
}
console.log("---" + this.array + "---");
for (var j = length; j > 1; j--)
{
change(j, 1); //将整理好的大顶堆数字最大的跟某位只交换,让末尾值最大
adjustHeap(1, j-1); //把最大值去除,即将上边移动的元素去除后重新整理成大顶堆
console.log("---" + this.array + "---");
}
console.log(this.array + "\n compareTime = " + compareTime + "\n changeTime = " + changeTime);
}
function adjustHeap(index, length) { //结点和长度
var temp = array[index]; //将结点的值放入temp
for (var j = 2 * index; j <= length; j *= 2) //沿关键字较大的孩子结点向下筛选
{
if (j < length && array[j] < array[j+1]) //判断孩子结点大小,以便取较大值跟结点交换
{
j++; //如果左孩子的值小于右孩子的值,则将下标增加一,让j指向大值的下标
}
compareTime ++;
if (temp >= array[j]) //判断结点和较大孩子结点的大小
{
break; //如果结点值大,跳出循环
}
compareTime ++;
array[index] = array[j]; //如果结点的值小,将大值赋给结点
index = j;
}
array[index] = temp; //交换值
}
/**
* 快速排序
* 基本思想:通过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,即可分别对着两部分
* 积蓄进行排序,以达到整个序列有序的目的。
* 复杂度:O(n㏒n)
* 稳定: 不稳定
* 注意:快速排序成为20世纪十大算法之一。
* @param i
* @param j
*/
function sortQ() {
sortQuick(0, array.length-1); //为了递归调用,单独写个排序的方法。
}
function sortQuick(low, high) {
var pivot = null; //枢轴
if (low < high)
{
pivot = partition(low, high); //将待排序数组一分为二,并返回枢轴的值
sortQuick(low, pivot-1); //对低子表递归排序
sortQuick(pivot+1, high); //对高子表递归排序
}
}
function partition(low, high) {
while (low < high)
{
var pivotKey = array[low]; //默认第一个数字为枢轴
while (low < high) //从表两端交替向中间扫描
{
while (low < high && array[high] >= pivotKey)
{
high--;
}
change(low, high); //将此枢轴记录小的记录交换到低端
while (low < high && array[low] <= pivotKey)
{
low++;
}
change(low, high); //将此枢轴记录大的记录交换到高端
}
}
return low; //返回枢轴所在位置
}
function change(i, j) { //交换位置
var temp = this.array[i];
this.array[i] = this.array[j];
this.array[j] = temp;
changeTime ++;
}
启动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
</script>
</head>
<body>
<button type="button" οnclick="refresh()">刷新</button>
<div id="show"></div>
<div id="result"></div>
</body>
<script src="src/sort/Sort.js"></script>
<script src="src/utils/Utils.js"></script>
<script type="text/javascript">
// sortBubble1();
// sortBubble2();
// sortBubble3();
// sortSelect();
// sortInsert();
// sortSheel();
// sortHeap();
sortQ();
function refresh() {
window.location = window.location;
}
document.getElementById("result").innerHTML = array;
</script>
</html>