day26 树的层序遍历 哈希表 排序算法 内核链表

实现树的层序遍历(广度遍历)

使用队列辅助实现二叉树的层序遍历。算法核心思想是:从根节点开始,依次将每一层的节点入队,出队时访问该节点,并将其左右子节点(若存在)加入队列,直到队列为空。

void LevelOrderTravel(TreeNode* root)
{SeqQue* sq = CreateSeqQue(20);  // 创建容量为20的顺序队列EnterSeqQue(sq, root);  // 根节点入队while(!IsEmptySeqQue(sq))  // 当队列非空时循环{DATATYPE* tmp = GetHeadSeqQue(sq);  // 获取队头元素(不删除)printf("%c", tmp->data);            // 访问当前节点数据if(tmp->left)                       // 若左子树存在,入队{EnterSeqQue(sq, tmp->left);}if(tmp->right)                      // 若右子树存在,入队{EnterSeqQue(sq, tmp->right);}QuitSeqQue(sq);  // 出队当前节点}printf("\n");  // 遍历结束后换行
}

理想运行结果
假设二叉树结构如下(按层序构建):

   A/ \B   C
/ \   \
D   E   F

输出结果为:ABCDEF


散列表查找(哈希表)

哈希表是一种通过哈希函数将关键字映射到表中位置的数据结构,目标是实现接近 O(1) 的平均查找时间。

哈希表结构定义

#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef int DATATYPE;// 哈希表结构体
typedef struct
{DATATYPE* head;  // 指向哈希表数组首地址int tlen;        // 哈希表长度
} HS_Table;

创建哈希表

HS_Table* CreateHsTable(int len)
{HS_Table* hs = malloc(sizeof(HS_Table));  // 分配哈希表结构体空间if (NULL == hs){perror("CreateHsTable malloc1");return NULL;}hs->head = malloc(sizeof(DATATYPE) * len);  // 分配数组空间if (NULL == hs->head){perror("CreateHsTable malloc2");return NULL;}hs->tlen = len;int i = 0;for (i = 0; i < len; i++){hs->head[i] = -1;  // 初始化所有位置为-1(表示空)}return hs;
}

说明:初始化时所有槽位设为 -1,作为“空位”标志。

哈希函数设计

/*** @brief 根据需要存储的数据,计算下标*  1. 计算过程尽可能简单 2. 下标均匀分布* @param h hashtable* @param data  需要计算下标的数据* @return int 下标*/
int HS_Fun(HS_Table* h, DATATYPE* data)
{return *data % h->tlen;  // 简单取模运算作为哈希函数
}

设计原则

  • 计算快捷方便
  • 地址分布均匀

插入操作(线性探测处理冲突)

int HS_Insert(HS_Table* h, DATATYPE* data)
{int ind = HS_Fun(h, data);  // 计算初始哈希地址// hash表的空间,一定要大于等于需要存储数据的个数while (-1 != h->head[ind])  // 若当前位置已被占用{printf("data:%d ind:%d\n", *data, ind);  // 打印冲突信息ind = (ind + 1) % h->tlen;  // 线性探测:向后移动一位(循环)}memcpy(&h->head[ind], data, sizeof(DATATYPE));  // 将数据复制到该位置return 0;
}

冲突处理方式:线性探测法(+1, +2, +3…)

查找操作

/*** @brief hs 查找函数** @param h hashtable* @param data 要找的数据* @return int 找到的下标 >=0  -1表示错误*/
int HS_Search(HS_Table* h, DATATYPE* data)
{int ind = HS_Fun(h, data);  // 计算初始哈希地址int old_ind = ind;          // 记录起始位置,用于判断是否已循环一圈while (*data != h->head[ind])  // 若当前值不匹配{ind = (ind + 1) % h->tlen;  // 继续线性探测if (ind == old_ind)         // 回到起点仍未找到{return -1;  // 查找失败}}return ind;  // 返回找到的位置
}

查找终止条件:找到匹配值或探测一圈后未发现。

主函数测试

int main(int argc, char** argv)
{HS_Table* hs = CreateHsTable(12);  // 创建长度为12的哈希表int array[12] = {12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34};int i = 0;for (i = 0; i < 12; i++){HS_Insert(hs, &array[i]);  // 逐个插入数据}int want_num = 12;int ret = HS_Search(hs, &want_num);if (-1 == ret){printf("can't find %d\n", want_num);  // 查找失败}else{printf("find it ,%d\n", want_num);  // 查找成功}return 0;
}

理想运行结果

data:12 ind:0
data:56 ind:8
data:16 ind:4
data:25 ind:1
data:37 ind:1
data:22 ind:10
data:29 ind:5
data:15 ind:3
data:47 ind:11
data:48 ind:0
data:34 ind:10
find it ,12

:由于 12 % 12 == 0,若 hs->head[0] 已被占用,则会触发冲突并打印提示。


排序

冒泡排序

  • 每次内循环将最大值“冒泡”至末尾
  • 相邻元素比较并交换
void bubble_sort(int a[], int len) {int i, j;for (j = len - 1; j > 0; --j)           // 外层控制排序轮数for (i = 0; i < j; ++i) {           // 内层比较相邻元素if (a[i] > a[i + 1]) {          // 若前大于后,则交换int t = a[i];a[i] = a[i + 1];a[i + 1] = t;}}return;
}

示例输入[5, 3, 8, 4, 2]
理想输出[2, 3, 4, 5, 8]

选择排序

  • 每轮选择最小元素放在最前面
  • 逐个比较,找到最小值后交换
void select_sort(int a[], int len) {int i, j;for (j = 0; j < len - 1; ++j)           // 外层控制已排序部分边界for (i = j + 1; i < len; ++i) {     // 内层寻找最小值if (a[j] > a[i]) {              // 若发现更小元素,则交换int t = a[i];a[i] = a[j];a[j] = t;}}
}

示例输入[5, 3, 8, 4, 2]
理想输出[2, 3, 4, 5, 8]

插入排序

  • 维护一个有序序列
  • 将待排元素插入到前面有序序列中的合适位置
void insert_sort(int a[], int len) {int i, j;for (i = 1; i < len; ++i) {             // 从第二个元素开始插入j = i;int t = a[j];                       // 保存当前待插入元素while (j > 0 && t < a[j - 1]) {     // 在有序部分中找插入位置a[j] = a[j - 1];                // 元素后移j--;}a[j] = t;                           // 插入正确位置}
}

示例输入[5, 3, 8, 4, 2]
理想输出[2, 3, 4, 5, 8]

快速排序

  • 分治策略
  • 选取基准(中枢),小的放左,大的放右
  • 递归处理左右子数组
void quick_sort(int a[], int len) {if (len < 1)return;int i = 0, j = len - 1, k;k = a[i];  // 取第一个元素为基准while (i < j) {while (k <= a[j] && i < j)  // 从右往左找小于k的元素j--;if (i < j)a[i] = a[j];  // 将较小元素移到左边while (k >= a[i] && i < j)  // 从左往右找大于k的元素i++;if (i < j)a[j] = a[i];  // 将较大元素移到右边}a[i] = k;  // 基准归位quick_sort(a, i);                    // 递归排序左半部分quick_sort(a + i + 1, len - 1 - i);  // 递归排序右半部分
}

示例输入[5, 3, 8, 4, 2]
理想输出[2, 3, 4, 5, 8]


内核链表

Linux 内核风格的双向循环链表实现,特点是数据域与指针域分离,提高通用性和复用性。

在这里插入图片描述

list.h

// 双向链表节点结构
// 仅包含指针域,不包含数据域(数据域与指针域分离)
struct list_head {struct list_head *next, *prev;  // 指向前后节点的指针
};// 初始化链表头节点(创建空链表)
// 使头节点的next和prev都指向自身,形成循环
static inline void INIT_LIST_HEAD(struct list_head *list)
{list->next = list;  // 头节点的next指针指向自身list->prev = list;  // 头节点的prev指针指向自身
}// 将新节点插入到链表头部(头插法)
// new: 要插入的新节点
// head: 链表头节点
static inline void list_add(struct list_head *new, struct list_head *head)
{__list_add(new, head, head->next);  // 调用底层函数,插入到头节点之后
}// 将新节点插入到链表尾部(尾插法)
// new: 要插入的新节点
// head: 链表头节点
static inline void list_add_tail(struct list_head *new,struct list_head *head)
{__list_add(new, head->prev, head);  // 调用底层函数,插入到头节点之前
}// 底层链表插入函数(内部使用)
// 将new节点插入到prev和next节点之间
static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)
{next->prev = new;  // 后节点的prev指针指向新节点new->next = next;  // 新节点的next指针指向后节点new->prev = prev;  // 新节点的prev指针指向前节点prev->next = new;  // 前节点的next指针指向新节点
}// 删除指定节点
// entry: 要删除的节点
static inline void list_del(struct list_head *entry)
{__list_del(entry->prev, entry->next);  // 调整前后节点的指针// 设置"中毒"指针,用于检测已删除节点的非法访问entry->next = LIST_POISON1;  // 标记next指针已失效entry->prev = LIST_POISON2;  // 标记prev指针已失效
}// 底层链表删除函数(内部使用)
// 将prev和next节点直接连接,跳过中间节点
static inline void __list_del(struct list_head *prev, struct list_head *next)
{next->prev = prev;  // 后节点的prev指针指向前节点prev->next = next;  // 前节点的next指针指向后节点
}// 安全遍历宏:可在遍历过程中安全删除当前节点
// pos: 用于遍历的当前节点指针(类型为包含list_head的结构体指针)
// n: 临时保存下一个节点的指针(用于在删除当前节点时继续遍历)
// head: 链表头节点
// member: 在结构体中list_head成员的名称
#define list_for_each_entry_safe(pos, n, head, member)                        \for (pos = list_entry((head)->next, typeof(*pos), member),                 \n = list_entry(pos->member.next, typeof(*pos), member);               \&pos->member != (head);                                               \pos = n, n = list_entry(n->member.next, typeof(*n), member))

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"// 人员结构体,包含业务数据和链表节点
typedef struct
{int id;char name[50];struct list_head node;  // 内嵌链表节点
} PER;// 添加人员节点
int add_per(struct list_head *head, int id, char *name)
{PER *per = malloc(sizeof(PER));if (NULL == per){perror("add_per malloc error\n");return 1;}per->id = id;strcpy(per->name, name);list_add_tail(&per->node, head);  // 插入链表尾部return 0;
}// 遍历并打印所有人员信息
int show(struct list_head *head)
{PER *tmp;PER *next;list_for_each_entry_safe(tmp, next, head, node)  // 安全遍历{printf("%d %s\n", tmp->id, tmp->name);}return 0;
}// 删除指定ID的人员
int del_per(struct list_head *head, int id)
{PER *tmp;PER *next;list_for_each_entry_safe(tmp, next, head, node)  // 安全遍历中删除{if (tmp->id == id){list_del(&tmp->node);  // 从链表中移除节点free(tmp);             // 释放内存}}return 0;
}// 主函数测试链表操作
int main(int argc, char **argv)
{struct list_head head;INIT_LIST_HEAD(&head);  // 初始化链表头add_per(&head, 1, "zhangsan");add_per(&head, 2, "lisi");add_per(&head, 3, "wangmazi");add_per(&head, 4, "guanerge");add_per(&head, 5, "liubei");show(&head);  // 显示所有人员del_per(&head, 1);  // 删除id为1的人员printf("------------del--------------\n");show(&head);  // 再次显示,验证删除效果return 0;
}

理想运行结果

1 zhangsan
2 lisi
3 wangmazi
4 guanerge
5 liubei
------------del--------------
2 lisi
3 wangmazi
4 guanerge
5 liubei

回顾

  • 哈希表 提供一种可用于高效存储与查找的数据结构,目标是实现查找时间复杂度在 O(1) 到 O(log N) 之间。
  • 核心概念:
    • fun(key) = 存储位置:哈希函数将关键字转换为数组下标
    • 存储空间通常为一段连续内存(哈希表)
  • 哈希函数设计原则
    1. 计算快捷、简便
    2. 地址分布均匀
  • 常见哈希函数(对数字):取模(key % table_size
  • 冲突处理方法
    • 线性探测:+1, +2, +3…
    • 二次探测:+1, -1, +4, -4…
    • 随机探测:使用随机数生成偏移
  • 内核链表
    • 双向循环链表
    • 节点仅含指针域,数据域独立(解耦)
    • 提高通用性与扩展能力
    • 支持安全遍历与动态删除(list_for_each_entry_safe

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/94514.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94514.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/94514.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【系统分析师】高分论文:论快速应用开发方法及应用

【摘要】 我在某县卫生健康委员会公共卫生信息中心工作&#xff0c;是信息中心的负责人。2021年5月&#xff0c;我中心受县痪病预防控制中心委托&#xff0c;为某种痪病疫苗3期临床项日开发受试对象拦截系统。我负责系统架构设计、需求分析以及后期的部分编码工作。通过与庆病预…

4056:【GESP2403八级】接竹竿

/*4056&#xff1a;【GESP2403八级】接竹竿flag 数组 存储每个元素出现的位置&#xff0c;nxt[i]j;存储每个位置 后面第一次出现 与a【i】相等的位置//其中 a【i]a[j] :记录i的下一个位置 &#xff0c;flag 存储每个值的位置下一次 具有下一次&#xff0c;相当于的链表了&…

企业落地版 AutoGen 多智能体工程(完整示例)

企业生产级参考实现,目标是一套可直接部署的模板工程,包含: FastAPI HTTP API(任务提交、状态查询) Celery 异步任务队列(Redis Broker) PostgreSQL + pgvector(向量存储,RAG) SQLAlchemy + Alembic(ORM 与迁移) AutoGen 多智能体编排(Planner / Coder / Executor…

前端的请求协议对应java的接收

application/json前端发送 JSON 数据&#xff0c;后端用 RequestBody 接收并自动映射为 Java 对象。前端示例&#xff08;Axios&#xff09;&#xff1a;axios.post("/api/user", { name: "张三", age: 20 }, {headers: { "Content-Type": "…

esp32_hid_device 调试遇到的一些问题

nimble to windows10 22h2esp_hid_device 的keyboardReportMap在win10 22h2 csr4.0 下好像识别不了&#xff0c; Windows&#xff08;和大多数 BIOS/UEFI&#xff09;只认 6-byte key array 的 HID Keyboard 描述符。如果不是 6 个字节&#xff0c;Windows HID 驱动就会认为这不…

观察者模式 (Observer Pattern)与几个C++应用例子

1. 模式定义与核心思想 观察者模式定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。当这个主题对象的状态发生变化时&#xff0c;它会自动通知所有观察者对象&#xff0c;使它们能够自动更新自己。核心思想&#xff1a; 解耦主题和观察者。主题…

[系统架构设计师]论文(二十三)

[系统架构设计师]论文&#xff08;二十三&#xff09; 一.论软件系统架构评估 1.架构所关注的质量属性主要有&#xff1a;性能&#xff0c;可用性&#xff0c;安全性&#xff0c;可修改性 1&#xff09;性能。性能是指系统的响应能力&#xff0c;即要经过多长时间才能对某个事件…

攻克 Java 分布式难题:并发模型优化与分布式事务处理实战指南

攻克 Java 分布式难题&#xff1a;并发模型优化与分布式事务处理实战指南 开场&#xff1a;从“摇摇欲坠”到“稳如磐石”&#xff0c;你的分布式系统进阶之路 你是否曾经遇到过这样的场景&#xff1f;精心打造的电商应用&#xff0c;在大促开启的瞬间&#xff0c;页面响应变得…

如何在Ubuntu中删除或修改已有的IP地址设置?

在 Ubuntu 中为新增加的网卡设置网络时&#xff0c;需要区分原有网卡和新网卡的配置&#xff0c;确保它们可以独立工作&#xff08;可在同一网段或不同网段&#xff09;。以下是具体步骤&#xff0c;假设你需要为新网卡配置静态 IP&#xff08;以 192.168.1.190/24 为例&#x…

Ansible Playbook 概述与实践案例(下)

#作者&#xff1a;张桐瑞 文章目录四、条件判断的实现五、循环的实现六、Jinja模板应用1、Jinja模板2、handlers组件七、角色 role1、角色介绍2、案例: 部署zabbix-agent四、条件判断的实现 when: 条件 - hosts: appserveruser: roottasks:- name: create userAuser: nameuser…

LeetCode 100 -- Day6

1. 哈希&#xff1a;49、128&#xff08;1&#xff09;49 字母异位词分组 -- 字典from collections import defaultdict class Solution(object):def groupAnagrams(self, strs):"""创建字典{sorted_string&#xff1a;原str}"""resultsdefaultd…

多因素认证(MFA/2FA)实战指南:如何保护你的账号

一、MFA/2FA 基础认知 1. 概念辨析与演进 单因素认证&#xff08;1FA&#xff09;的局限性&#xff1a;仅依赖 “知识因素”&#xff08;如密码&#xff09;&#xff0c;据 2024 年 Verizon 数据泄露报告&#xff0c;81% 的账户入侵源于密码泄露 —— 要么是用户使用弱密码&a…

vue3 字符 居中显示

在Vue 3中&#xff0c;要实现字符的居中显示&#xff0c;你可以使用多种方法&#xff0c;具体取决于你是想在HTML元素内居中文本&#xff0c;还是在CSS样式中实现。下面是一些常见的方法&#xff1a;1. 使用内联样式你可以直接在元素上使用style属性来实现文本的居中。<temp…

《Spring Boot 进阶:从零到一打造自定义 @Transactional》 ——支持多数据源、动态传播行为、可插拔回滚策略

《Spring Boot 进阶&#xff1a;从零到一打造自定义 Transactional》 ——支持多数据源、动态传播行为、可插拔回滚策略版本&#xff1a;Spring Boot 3.2.x JDK 17一、背景与痛点痛点默认 Transactional 限制多数据源只能绑定一个 DataSourceTransactionManager多租户无法在运…

open3D学习笔记

这里写自定义目录标题 核心3D数据结构 1.1 PointCloud(点云) 最近邻搜索 (KNN/Radius) 与空间索引(KDTree/Octree) 法线估计 (Normal Estimation) 聚类分割 (基于欧氏距离的聚类) 1.2 TriangleMesh (三角形网格) 泊松表面重建 (Poisson Surface Reconstruction) 滚球法 (Ba…

gt_k_char设计模块

是不是再fiber或者gt设计中经常遇到接收数据没有对齐&#xff1f;是的。很多协议需要手动对齐设计。这不&#xff0c;它来了。下面是手动对齐代码设计&#xff0c;本人在很多工程和项目中应用过&#xff0c;现在共享出来&#xff0c;给大家使用。module gt_k_char (input …

网页版云手机怎么样

随着科技的不断发展&#xff0c;云手机这一新兴概念逐渐走入大众视野&#xff0c;而网页版云手机作为云手机的一种便捷使用方式&#xff0c;备受关注&#xff0c;下面从多个方面来探讨网页版云手机究竟怎么样。与传统的需要在本地设备安装专门APP的云手机使用方式不同&#xff…

XFile v2 系统架构文档

XFile v2 系统架构文档 1. 概述 XFile 是一个基于 Go 语言开发的分布式文件管理系统&#xff0c;提供本地文件存储、网络文件共享、安全认证和多种文件操作功能。该系统采用模块化设计&#xff0c;支持大文件分片存储、用户权限管理、双因素认证等高级功能。 XFile系统的核心特…

写一个天气查询Mcp Server

上篇文章&#xff0c;我们聊到了 MCP 的基本概念&#xff0c;带大家快速入门了 MCP。 说入门应该毫不夸张&#xff0c;对于科普性质的文章&#xff0c;只需要知道这件事情的诞生背景以及有什么作用就可以了。 但是&#xff0c;如果要开发给大模型调用的 Mcp Server&#xff0…

leecode-三数之和

思路 我的思路先顺序遍历一个变量,然后使用首尾双指针去遍历&#xff0c;根据结果去更新另外两个变量&#xff0c;如何和为零&#xff0c;将结果加入集合&#xff0c;但是这里要注意去重。 class Solution {public List<List<Integer>> threeSum(int[] nums) {// 排…