跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

堆数据结构与字符串处理算法详解

堆数据结构基础概念、插入删除及建堆操作详解,配合 C++ 代码实现最大堆与堆排序。涵盖常见字符串处理算法,包括字母异位词判断、字符串两半相似性检测、末尾单词长度计算及回文串验证。利用双指针与哈希计数技巧优化时间复杂度,辅以堆相关选择题解析,掌握核心算法逻辑与面试考点。

Elasticer发布于 2026/3/25更新于 2026/5/2012 浏览
堆数据结构与字符串处理算法详解

堆数据结构与字符串处理算法详解

一、堆数据结构基础

堆(Heap)是一种特殊的完全二叉树,根据性质可分为最大堆和最小堆。最大堆中每个节点的值都大于或等于其子节点,最小堆则相反。通常使用数组实现,对于索引为 i 的元素:

  • 左子节点位置:2*i + 1
  • 右子节点位置:2*i + 2
  • 父节点位置:(i-1)/2

堆的基本操作

核心操作包括插入元素(上浮)、删除堆顶(下沉)以及建堆。

#include <vector>
#include <iostream>

class MaxHeap {
private:
    std::vector<int> heap;

    // 上浮操作
    void heapifyUp(int index) {
        int parent = (index - 1) / 2;
        if (index > 0 && heap[index] > heap[parent]) {
            std::swap(heap[index], heap[parent]);
            heapifyUp(parent);
        }
    }

    // 下沉操作
    void heapifyDown(int index) {
        int largest = index;
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        int size = heap.size();

        if (left < size && heap[left] > heap[largest]) {
            largest = left;
        }
        if (right < size && heap[right] > heap[largest]) {
            largest = right;
        }

         (largest != index) {
            std::(heap[index], heap[largest]);
            (largest);
        }
    }

:
    
    {
        heap.(value);
        (heap.() - );
    }

    
    {
         (heap.()) {
             std::();
        }
         max = heap[];
        heap[] = heap.();
        heap.();
         (!heap.()) {
            ();
        }
         max;
    }

    
    {
        heap = array;
         ( i = heap.() /  - ; i >= ; i--) {
            (i);
        }
    }

    
    {
         ( value : heap) {
            std::cout << value << ;
        }
        std::cout << std::endl;
    }

    {  heap.(); }
    {  heap.(); }
};
if
swap
heapifyDown
public
// 插入元素
void insert(int value)
push_back
heapifyUp
size
1
// 删除堆顶元素
int extractMax()
if
empty
throw
out_of_range
"Heap is empty"
int
0
0
back
pop_back
if
empty
heapifyDown
0
return
// 建堆
void buildHeap(const std::vector<int>& array)
for
int
size
2
1
0
heapifyDown
// 打印堆
void printHeap()
for
int
" "
int size()
return
size
bool empty()
return
empty

堆排序

堆排序利用堆的性质进行排序,主要步骤是构建最大堆,然后反复将堆顶元素移至末尾并调整堆结构。

void heapSort(std::vector<int>& arr) {
    int n = arr.size();
    // 构建最大堆
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(arr, n, i);
    }
    // 一个个从堆顶取出元素
    for (int i = n - 1; i > 0; i--) {
        std::swap(arr[0], arr[i]);
        heapify(arr, i, 0);
    }
}

void heapify(std::vector<int>& arr, int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && arr[left] > arr[largest]) {
        largest = left;
    }
    if (right < n && arr[right] > arr[largest]) {
        largest = right;
    }
    if (largest != i) {
        std::swap(arr[i], arr[largest]);
        heapify(arr, n, largest);
    }
}

堆排序时间复杂度为 O(nlogn),空间复杂度为 O(1)。

二、字符串处理算法

1. 有效的字母异位词

判断两个字符串是否包含相同的字符且频率一致。

class Solution {
public:
    bool isAnagram(string s, string t) {
        if (s.length() != t.length()) {
            return false;
        }
        std::vector<int> char_counts(26, 0);
        for (int i = 0; i < s.length(); ++i) {
            char_counts[s[i] - 'a']++;
            char_counts[t[i] - 'a']--;
        }
        for (auto count : char_counts) {
            if (count != 0) {
                return false;
            }
        }
        return true;
    }
};

思路很简单,用数组统计字符频次差值。遍历完如果全为 0,说明互为异位词。时间复杂度 O(n)。

2. 判断字符串的两半是否相似

给定偶数长度字符串,比较前后两半元音字母数量是否相同。

class Solution {
public:
    bool isVowel(char c) {
        c = tolower(c);
        return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
    }

    bool halvesAreAlike(string s) {
        int begin = 0;
        int count1 = 0;
        int end = s.size() / 2;
        int count2 = 0;

        while (end < s.size()) {
            if (isVowel(s[begin])) count1++;
            if (isVowel(s[end])) count2++;
            begin++; end++;
        }
        return count1 == count2;
    }
};

双指针同步遍历,分别计数即可。

3. 字符串最后一个单词的长度

计算字符串末尾单词长度,需处理空格情况。

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    getline(cin, s);
    size_t pos = s.rfind(' ');
    if (pos != string::npos) {
        cout << s.size() - pos - 1 << endl;
    } else {
        cout << s.size() << endl;
    }
    return 0;
}

使用 rfind 从后找空格,若找到则计算剩余长度,否则整个串即为单词。

4. 验证回文串

只考虑字母数字,忽略大小写。

class Solution {
public:
    bool isPalindrome(string s) {
        int begin = 0;
        int end = s.size() - 1;
        while (begin < end) {
            while (begin < end && !isalnum(s[begin])) begin++;
            while (begin < end && !isalnum(s[end])) end--;
            if (tolower(s[begin]) != tolower(s[end])) {
                return false;
            }
            begin++; end--;
        }
        return true;
    }
};

双指针向中间靠拢,跳过非有效字符后比较。注意 tolower 转换。

三、堆相关选择题解析

1. 下列哪个关键码序列是一个堆? A. 94,31,53,23,16,72 B. 94,53,31,72,16,23 C. 16,53,23,94,31,72 D. 16,31,23,94,53,72

解析: 选项 D 对应最小堆结构:根节点 16 小于子节点 31 和 23;31 小于 94 和 53;23 小于 72。满足最小堆性质。 答案:D

2. 将关键字序列 50, 40, 95, 20, 15, 70, 60, 45, 80 调整成一个小根堆,堆结构是 15,20,60,45,40,70, 95,50,80,该说法正确吗? 解析: 检查父子关系:15<20, 15<60;20<45, 20<40;60<70, 60<95;45<50, 45<80。所有节点均满足小根堆性质。 答案:A

3. 已知序列 25, 13, 10, 12, 9 是大根堆,插入新元素 18,调整为大根堆,比较次数是? 解析: 插入 18 到末尾,父节点为 10。18>10,交换(第 1 次比较)。新父节点为 25。18<25,停止(第 2 次比较)。 答案:B

4. 已知关键字序列 5,8,12,19, 28, 20, 15,22 是小根堆,插入关键字 3,调整后得到的小根堆是? 解析: 插入 3 后上浮。3<19 交换,3<8 交换,3<5 交换。最终堆顶为 3,顺序为 3, 5, 12, 8, 28, 20, 15, 22, 19。 答案:A

5. 在堆排序的过程中,建立一个堆的时间复杂度是? 解析: 虽然单次下沉是 O(logn),但建堆是从最后一个非叶子节点开始,大部分节点下沉距离很短。数学推导证明总复杂度为 O(n)。 答案:A


掌握堆的底层逻辑和常见字符串技巧,对理解优先队列及面试高频题很有帮助。实际编码时注意边界条件,比如空指针或越界访问。

目录

  1. 堆数据结构与字符串处理算法详解
  2. 一、堆数据结构基础
  3. 堆的基本操作
  4. 堆排序
  5. 二、字符串处理算法
  6. 1. 有效的字母异位词
  7. 2. 判断字符串的两半是否相似
  8. 3. 字符串最后一个单词的长度
  9. 4. 验证回文串
  10. 三、堆相关选择题解析
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Whisper v0.2 本地语音转文字工具安装与使用指南
  • JSON-java CDL转换终极指南:快速掌握逗号分隔列表与JSONArray互转技巧
  • Python 为何成为 AI 开发首选?技术特性与生态全景解析
  • GitHub Copilot SDK 与云原生多智能体系统构建
  • C++ 二叉搜索树简单实现:增删查改详解
  • GitHub Copilot 上下文工程实战指南与 7 个核心技巧
  • 零基础转行大数据:Python 技术栈学习路线与实战指南
  • 数据结构基础:顺序表的定义与实现
  • 从第一性原理看大模型 Agent 技术
  • GitHub Copilot 接入 Figma MCP 还原设计稿生成前端代码
  • 快速排序非递归实现详解:手动模拟栈结构
  • Python 文档处理实战:python-docx 库详解与应用
  • Linux 命令行趣味工具集锦
  • 医疗连续体机器人模块化控制界面设计与 Python 库应用
  • CosyVoice 安装 openai-whisper 报错 pkg_resources 缺失原因及解决
  • Python 使用 Streamlit 提取 PDF 文档文字
  • C++11 列表初始化、新式声明、范围 for 与 STL 变化
  • Claude Code 与 ChatGPT、Copilot 的核心区别是什么?
  • 归并排序非递归实现指南
  • 从零构建 AI 对话平台:原生前端实战指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online