惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 聂微东
罗磊的独立博客
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
LINUX DO - 最新话题
Webroot Blog
Webroot Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
T
Tenable Blog
Help Net Security
Help Net Security
WordPress大学
WordPress大学
H
Heimdal Security Blog
SecWiki News
SecWiki News
V2EX - 技术
V2EX - 技术
C
CERT Recently Published Vulnerability Notes
P
Privacy International News Feed
T
Tailwind CSS Blog
L
LINUX DO - 热门话题
Scott Helme
Scott Helme
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
O
OpenAI News
Latest news
Latest news
月光博客
月光博客
L
LangChain Blog
Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
I
InfoQ
T
Threat Research - Cisco Blogs
人人都是产品经理
人人都是产品经理
Forbes - Security
Forbes - Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园_首页
雷峰网
雷峰网
T
Tor Project blog
Security Archives - TechRepublic
Security Archives - TechRepublic
G
GRAHAM CLULEY
Project Zero
Project Zero
MyScale Blog
MyScale Blog
V
V2EX
Vercel News
Vercel News
F
Fortinet All Blogs
The Register - Security
The Register - Security
N
News and Events Feed by Topic
P
Palo Alto Networks Blog
H
Hacker News: Front Page
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 司徒正美

Victrid's Personal Site

斯普拉遁3打工模式联机网络过程分析 DHCP无类型静态路由──一个摆设 配置透明代理,实现无感上网 Generating Unlimited Grammar: A Messenger Perspective LaTeX插入其他PDF中的矢量图 光速不变原理和迈克尔孙──莫雷实验 交大葡萄演义 调试微信内置浏览器 欧悌甫戎篇 苏格拉底的申辩篇 LCA 最近公共祖先 弥罗斯人的辩论 埃斯库罗斯作品:波斯人、阿伽门农 电路理论资料 Coronavirus: A Humanitarian Crisis 雨夜 linux配置SSR 懒政 Placement New Flipped: A Love Story 我宁可呆在这样的疯人院里 谈新发本地病例 勇敢与智慧 Powerful but Limited Drafted VLC Libva Error Troubleshooting Ring-Fit新上手 政治艺术化与艺术政治化 动态规划——从分割等和子集入手 被背叛的革命 (1) Everything About DPT-RP1 When Using LINUX HTTP STATUS 451 二分法——重复情形 鸽巢排序与桶排序 为什么要写博客 系统更换 动窗法与前缀和——简单实践 非类型模板参数 判断的短路规则 CodeBlocks重装 C-Style String Operation
二叉堆的实现
Victrid · 2020-04-07 · via Victrid's Personal Site

我一直以为实现一个二叉堆是很困难的事情,还以为会用到树翻转这种经典梗问题,结果自己实现了一下,发现非常简单,甚至比传统的几个排序:快速排序、归并排序还要简单、好写的多。

堆这种数据结构,目的是实现一种优先队列。它可以在比较好的复杂度下实现优先队列的各项操作。

二叉堆的实现,典型的使用的是线性存储,这一点和线段树比较像(原谅我这几天写了太多的线段树,脑子都写迷糊了)。

构建方式采用的是上浮法。通过让每一个节点与父节点比较,如果节点比他的父节点更加优先,就将其递归的上浮,直到根节点。这样可以对每一个结构进行遍历。

从此处我们可以看出,需要注意的是,二叉堆并不是一颗搜索树。它只能保证顶端节点是最优先的节点,而不能对其他任何节点给出判断。因此二叉堆是不能用于静态查询的。通常的静态应用会采用二叉堆进行一次排序。

给出一段上浮的示例代码:(和线段树一样,这里通常采用一个1-base的数组)

1
2
3
4
5
6
7
8
9
void siftup(int node) {
if (node == 1 || node == 0)
return;
if (storage[node] < storage[node >> 1]) {
swap(storage[node], storage[node >> 1]);
siftup(nodec >> 1);
}
return;
}

堆可以比较高效率的实现优先队列的入队与出队。

对于一个入队过程,只需要将元素放到最后一位,然后对其执行上浮即可。这一点和构建一个堆是等价的。

对于一个出队过程,显然,我们已经知道出队的元素在堆的顶端。我们抽走队列的头节点,然后把队列的尾部放到头节点的位置。此后我们执行一个下沉的操作。对一个节点的两个子节点,对各个子树递归的下沉。需要注意的是,两颗子树都要进行下沉的判断工作,因为如前文所述,堆只有头部是满足最优先,而对其他的数据给不出任何判断。

给出一段下沉的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
void heapify(int node, int treesize) {
if (node >= treesize)
return;
if (node << 1 <= treesize && storage[node] > storage[node << 1]) {
swap(storage[node], storage[node << 1]);
heapify(node << 1, treesize);
}
if ((node << 1 | 1) <= treesize && storage[node] > storage[node << 1 | 1]) {
swap(storage[node], storage[node << 1 | 1]);
heapify(node << 1 | 1, treesize);
}
return;
}

到此为止,这个过程非常简单。甚至来讲,我们把“把队列的尾部放到头节点的位置”换成“把队列的尾部和头节点交换”,我们就实现了一个原地的堆排序。这个排序方向和堆的优先方向是相反的。

Author: Victrid

Permanent Link: https://victrid.dev/2020/dui-de-shi-xian/

License: Copyright (c) 2025 victrid Terms of Use

Ads by Google

Read our privacy policy on how these personalized advertisements are delivered to you.

For your reading experience, we provide full-text RSS feeds. Although math formulas cannot be displayed well, the interface can be adjusted as you like and there are no ads.