常见排序算法与数据结构(Javascript版)

哈希表: hash 算法 + 数组/链表

    解决 hash 冲突:
        1 链地址法
        2 开放地址法(空白元素偏移)
           (线性探测、二次方探测、再哈希法)

    hash 算法提升计算速度:霍纳法则/秦九韶算法

    数组元素使其分布均匀:常量使用质数

function hashFunc(str, size) {
    let hashcode = 0;
    // 使用霍纳法则,37为一个较大的质数常量
    str.split('').forEach(char => hashcode = 37 * hashcode + charCodeAt(char)); 
    return hashcode % size;
}

排序:

function Sort(arr) {
    this.arr = arr;
    this.arrLength = arr.length;
}
// 希尔排序
/* 
arr = [41, 36, 39, 25, 59, 47, 28, 35, 16], 
length = 9
*/
Sort.prototype.shellSort = function() {
    // 偏移量
    var gap = Math.floor(this.arrLength / 2);
    for(; gap > 0; gap = Math.floor(gap / 2)) {
        var index = gap;
        for(; index < this.arrLength; index += gap) {
            var temp = this.arr[index];
            var subIndex = index;
            for(; subIndex - gap >= 0 && this.arr[subIndex - gap] > temp; subIndex -= gap ) {
                this.arr[subIndex] = this.arr[subIndex - gap];
            }
            this.arr[subIndex] = temp;
        }
    }
}

// 快速排序
Sort.prototype.quickSort = function(initBeginIdx, initEndIdx) {
	// console.log("quickSort", {initBeginIdx, initEndIdx});
	var beginIdx = initBeginIdx || 0;
	var endIdx = initEndIdx || (this.arrLength - 1);
	// 设置中间元素 = arr[0], arr[Math.floor(len / 2)], arr[len -1] 的中位数
	let midPosition = Math.floor((beginIdx + endIdx) / 2);
	if(midPosition === 0) {
		return this.arr;
	}

	var midElement = this.arr[midPosition];
	if(this.arr[0] > this.arr[midPosition]) {
		midElement = this.arr[0];
		this.arr[0] = this.arr[midPosition];
	}
	if(this.arr[this.arrLength - 1] < this.arr[midPosition]) {
		midElement = this.arr[this.arrLength - 1];
		this.arr[this.arrLength - 1] = this.arr[midPosition];
	}
	this.arr[midPosition] = midElement;
	// this.toString();

	// 小于 中间数字 的元素放在 左边,
	// 大于 中间数字 的元素放在 右边
	while(beginIdx <= endIdx) {
		while(this.arr[beginIdx] < midElement) {
			beginIdx += 1;
		}
		if(beginIdx >= endIdx) {
			break;
		}
		this.arr[midPosition] = this.arr[beginIdx];
		midPosition = beginIdx;
		// console.log("midPosition", midPosition);
		
		while(this.arr[endIdx] > midElement) {
			endIdx -= 1;
		}
		if(beginIdx >= endIdx) {
			break;
		}
		this.arr[midPosition] = this.arr[endIdx];
		midPosition = endIdx;
		// console.log("midPosition", midPosition);
	}
	this.arr[midPosition] = midElement;

	// 对前后数组分而治之,进行递归
	if((midPosition - 1) > (initBeginIdx || 0)) {
		this.quickSort(initBeginIdx || 0, midPosition - 1);
	}
	if((initEndIdx || (this.arrLength - 1)) > (midPosition + 1)) {
		this.quickSort(midPosition + 1, initEndIdx || (this.arrLength - 1));
	}
}

Sort.prototype.toString = function() {
    console.log("arr", this.arr.join(','));
}

var arr = [22,21,63,1,12,54,3,23];
var sort = new Sort(arr);
sort.shellSort();
sort.toString();
// 堆排序
function Sort(arr) {
	this.arr = arr;
	this.arrLength = arr.length;
}

Sort.prototype.swap = function(firstIdx, secondIdx) {
	var temp = this.arr[firstIdx];
	this.arr[firstIdx] = this.arr[secondIdx];
	this.arr[secondIdx] = temp;
}

Sort.prototype.heapify = function (parentIdx) {
	var arrMaxIdx = this.arr.length - 1; // 最大下标
	var lChildIdx = parentIdx * 2 + 1; // 左子节点坐标
	var rChildIdx = parentIdx * 2 + 2; // 右子节点坐标
	var maxIdx = parentIdx; // 默认父节点值最大
	if(lChildIdx <= arrMaxIdx && this.arr[lChildIdx] > this.arr[maxIdx]) {
		maxIdx = lChildIdx;
	}
	if(rChildIdx <= arrMaxIdx && this.arr[rChildIdx] > this.arr[maxIdx]) {
		maxIdx = rChildIdx;
	}
	if(maxIdx !== parentIdx) {
		// 交换数据
		this.swap(parentIdx, maxIdx);
		// 回调 heapify 交换后的子节点
		this.heapify(maxIdx);
	}
}

Sort.prototype.arrayHeapify = function() {
	var arrMaxIdx = this.arr.length - 1; // 最大下标
	let startIdx = Math.floor((arrMaxIdx - 1) / 2); // 找到完全二叉树的最后一个非子节点
	for(var i = startIdx; i >= 0; i--) {
		this.heapify(i);
		// sort.toString();
	}
}

// 堆排序
Sort.prototype.heapSort = function() {
	let resultArr = [];
	while(this.arr.length > 0) {
		this.arrayHeapify();
		// 将坐标为0(最大值)和最后一个元素值交换
		this.swap(0, this.arr.length - 1);
		resultArr.unshift(this.arr.pop());
	}
	this.arr = resultArr;
}

Sort.prototype.toString = function() {
	console.log("arr", this.arr.join(','));
}

var arr = [22,21,63,1,12,54,3,23];
var sort = new Sort(arr);
sort.heapSort();
sort.toString();

排序比较:

排序算法平均时间复杂度最好情况最差情形稳定度空间复杂度排序方式备注
冒泡排序O(n^2)O(n)O(n^2)YO(1)交换

 n值小 时较好

插入排序O(n^2)O(n)O(n^2)YO(1)插入大部分有序 时较好
选择排序O(n^2)O(n^2)O(n^2)NO(1)选择n值小 时较好
希尔排序O(n^(3/2))O(nlog2^n)O(n^2)NO(1)插入n值中等大小 时较好
快速排序O(nlog2^n)O(nlog2^n)O(n^2)NO(log2^n)交换n值大 时较好,有序时较差
堆排序O(nlog2^n)O(nlog2^n)O(nlog2^n)NO(1)选择n值中等大小 时较好
        
归并排序O(nlog2^n)O(nlog2^n)O(nlog2^n)YO(n)归并n特别大 需要硬件存储
计数排序O(n + k)O(n + k)O(n + k)YO(k) n特别大 需要硬件存储
桶排序O(n + k)O(n + k)O(n^2)YO(n + k) n特别大 需要硬件存储
基数排序O(n * k)O(n * k)O(n * k)YO(n + k) n特别大 需要硬件存储
        

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值