堆排序js

本文详细介绍了堆排序算法,包括其执行流程、代码实现和图片演示。堆排序是一种基于完全二叉树结构的排序算法,具有O(n*logn)的时间复杂度和O(1)的空间复杂度。在堆排序过程中,首先构建大顶堆,然后通过交换堆顶元素与末尾元素并重新调整堆来实现排序。代码实现部分展示了如何创建和维护堆,以及如何逐步完成排序过程。堆排序适用于需要原地排序且不额外占用大量内存的场景。
摘要由CSDN通过智能技术生成

目录

前言

一、执行流程

二、代码实现

三、图片演示

总结


前言

“堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。”

堆排序 时间复杂度O(n*log n) 空间复杂度O(1)
         可以自由添加数据,但取出数据时要从最小值开始按顺序取出。
         结点的排列顺序为从上到下,同一行里则为从左到右。
        子结点必定大于父结点。(小顶堆) 父结点必定大于子结点。(大顶堆)

        往堆中添加数据时,为了遵守这条规则,一般会把新数据放在最下面一行靠左的位置。
        当最下面一行里没有多余空间时,
        就再往下另起一行,把数据加在这一行的最右端。


一、执行流程


        1对序列进行原地建堆(heapify) 如果父元素改变位置就要递归了 恢复堆的规则
        2递归重复 执行以下操作.直到堆的元素数量为1
             交换堆顶元素与尾元素
             堆的元素数量减1
             堆数组索引[0]进行heapify操作


二、代码实现




		//大顶堆
		// let arr = [1, 4, 6, 5, 3, 7, 2]
		// let arr = [80, 43, 50, 21, 38, 14]
		// let arr = [7, 5, 1, 6, 4, 2, 3]
		// let arr = [50, 21, 80, 43, 38, 14]
		// let arr = [7,6,5,4,3,2,1]
		// let arr = [1,5,4,3,6,7,2]
		// let arr = [1,1,2,3,3,2,2]
		// let arr = [1,1,2,3,22]
		let arr = [9,8,7,6,5,0,1,2,4,3]
		
        heap_sort(arr, arr.length)
		console.log(arr)
		//建堆 制定堆的规则 运行是从下面开始的 这里只是制定规则
		// arr : 当前数组
		// n : 数组的长度 因为会发生变化所以要接一下
		// i : 让这个节点 符合堆的规则 这是因为后期传来的值会导致堆的规则发生变化
		function heapify(arr, n, i) {
			let temp; //用来交换位置
			let largest = i //代表父节点
			let lson = i * 2 + 1 // 左孩子节点
			let rson = i * 2 + 2 // 右孩子节点
			//不能超出数组长度 会浪费时间 而且后期不能让他跟最后一个元素(n-1)比较
			// 因为最大的被换位置到了最后面,所以不能让他们比较
			if (lson < n && arr[largest] < arr[lson]) {
				largest = lson
			}

			if (rson < n && arr[largest] < arr[rson]) {
				largest = rson
			}
			//父节点如果不是以前的i说明有一个孩子比他大,所以要换位置
			if (largest != i) {
				temp = arr[i]
				arr[i] = arr[largest]
				arr[largest] = temp
				//但是换位置就发现,破坏了堆的规则 所以我们又要执行一次
				//arr : 数组 n : 数组长度 要维护父节点所以要对父节传进去换位置
				heapify(arr, n - 1, largest)
			}
		}

		// 上面是制定规则 当是运行还是从这里开始 
		//我们只需要二个参数 不需要i 因为i的节点的维护交给heapify
		//我们只要传arr数组和长度就行
		function heap_sort(arr, n) {
			let temp = null//交换位置
			// Math.floor(arr.length / 2) - 1代表最后一个父节点 因为是从最后一个父节点开始比较的
			// let arr = [7, 3, 4, 2, 5, 1, 6] length 7 / 2 - 1 = 数组索引2 
			// i >= 0 是因为他还有索引为0的父节点也是大顶堆的最大数
			//i --  是因为先从右开始比较维护在从左 最后一个索引0就是大顶
			// 这个for循环执行完就代表堆的规则执行完了
			for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) {
				// 代码是在这里运行的 上面的heapify虽然写了但是堆还是没有制定规则 只有这里执行完才制定规则
				heapify(arr, n, i)
			}

			//最复杂的地方
			for (let i = n - 1; i > 0; i--) {
				// 这个地方实现的效果是 最大的与最后面的换位置 
				temp = arr[0]
				arr[0] = arr[i]
				arr[i] = temp
				// i 代表数组长度必须要传给heapify的长度
				//而且这个i每次必须-- 不然在heapify里面执行的时候就会动最后的元素
				// 这个0就是因为最大跟的跟最后面的换位置了 
				// 然后最后面的就变成了数组的0位 然后他又不是最大的所以又要重新制定规则
				heapify(arr, i, 0)
			}
		}

 

 

三、图片演示


 

总结

基本思想将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值