java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846
文章目录
堆排序是利用堆(数据结构)设计的排序算法,属于选择排序,最坏,最好,平均时间复杂度均为O(n logn),不稳定排序 堆是具有以下性质的完全二叉树: 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆 不对结点的左孩子的值和右孩子的值的大小关系进行要求。 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
堆排序,就是符合一定规则的完全二叉树,这个规则是:整个二叉树中,你随便挑出一颗子树,都满足根结点>=左右孩子(大根堆)或者根结点<=左右孩子(小根堆) 所以如果我们采用从下往上构建堆,是比较方便的。只需要关注当前的子树满足指定规则即可 例如我们想要构建一个长度为4的小顶堆,需要插入的元素是[3,2,3,1,2,4,5,5,6],我们想要实现,保留[3,2,3,1,2,4,5,5,6]中最大的4个在小顶堆中 先无脑插入4个结点,因为我们的堆长度为4,heap=[3,2,3,1] 然后调整堆,从第一个非叶子结点开始调整,利用完全二叉树公式len/2-1是第一个非叶子,len/2-2是第二个非叶子,依次类推 第一个非叶子结点root为4/2 - 1 = 1,也就是heap[1] = 2. 然后根据完全二叉树公式获取其左右孩子,left = root * 2+1 和 right = root * 2+2。也就是left = 1 * 2+1 = heap[3] = 1.right = 1 * 2+2 = 4,超出堆大小,没有右孩子。 此时我将让root和left以及right比较,谁小谁做根结点。发现root = heap[1] = 2 > left = heap[3] = 1.故root下降到left位置,left上升到root位置。 从而堆变成heap = [3,1,3,2] 第二个非叶子结点root为4/2-2 = 0,也就是heap[0] = 3, 其left = 0 * 2 +1 = heap[1] = 1.其right = 0 * 2+2 = heap[2] = 3. 比较后发现,root>left,因此进行root下降到left操作,也就是交换位置swap(root,left),此时heap = [1,3,3,2] 然后发现此时root指向原来left位置,也就是下降一次后,root = heap[1] = 3,我们发现它还有一个左孩子left = 1 * 2+1 = heap[3] = 2. 我们发现root>left,因此root继续下降,此时heap = [1,2,3,3] 堆构建完成后,我们进行插入操作,现在该插入第5个结点,[2],我们发现[2]>堆顶的[1].因此[1]肯定不是序列中最大的4个中的一个,所以我们将堆顶元素heap[0] 换为 [2].然后重新回到上面的调整堆的操作。也就是不断下降的操作,直到[2]下降到符合小根堆的位置。 依次类推,直到所有元素处理完成,就构建完成了一个小顶堆
用到的公式(二叉树的基本公式) arr[i]<=arr[2 * i+1] && arr[i] <= arr[2 * i+2] 小顶堆条件,当前非叶子节点arr[i],左节点和右节点,都小于它,大顶堆正好相反,左右都大于它本身 第一个非叶子节点arr.length/2-1 当前节点的左子节点,i * 2+1,当前节点右子节点i * 2+2
直接实现小根堆难免让人不知道这是干什么用的,因此,用一道算法题来理解。这道题的代码完全就是小根堆的代码。
🏆LeetCode215. 数组中的第K个最大元素https://blog.csdn.net/grd_java/article/details/136932454
class Solution { public int findKthLargest ( int [ ] nums, int k) { int [ ] minHeap = new int [ k] ; for ( int i = 0 ; i < k; i++ ) { minHeap[ i] = nums[ i] ; } for ( int i = k / 2 - 1 ; i >= 0 ; i-- ) { adjustHeap ( minHeap, i) ; } for ( int i = k; i < nums. length; i++ ) { if ( nums[ i] > minHeap[ 0 ] ) { minHeap[ 0 ] = nums[ i] ; adjustHeap ( minHeap, 0 ) ; } } return minHeap[ 0 ] ; } private void adjustHeap ( int [ ] array, int root) { while ( true ) { int left = 2 * root + 1 ; int right = left + 1 ; int min = root; if ( left < array. length && array[ left] < array[ min] ) min = left; if ( right < array. length && array[ right] < array[ min] ) min = right; if ( min == root) break ; swap ( array, root, min) ; root = min; } } private void swap ( int [ ] array, int i, int j) { int temp = array[ i] ; array[ i] = array[ j] ; array[ j] = temp; }
}