当前位置: 首页 > news >正文

数据结构与算法启示

从整体到细节,自顶向下,从抽象到具体的框架思维是通用的,不只是学习数据结构和算法,学习其他任何
知识都是高效的
数据结构是工具,算法是通过合适的工具解决特定问题的方法
一、数据结构的存储方式
存储:数组(顺序存储) 链表(链式存储)
我们分析问题,一定要有递归的思想,自顶向下,从抽象到具体。
*比如 队列 ,栈 这两种数据结构既可以用链表也可以用数组
用数组考虑 处理扩容缩容的问题
用链表考虑内存空间存储结点指针
*图 的两种表示方式邻接表就是链表 邻接矩阵就是二维数组
邻接矩阵判断连通性迅速
图比较稀疏用邻接表节省空间
*「散列表」就是通过散列函数把键映射到一个大数组里。
而且对于解决散列冲突的方法,拉链法需要链表特性,操作简单,但需要额外的空间存储指针;
线性探查法就需要数组特性,以便连续寻址,不需要指针的存储空间,但操作稍微复杂些。
*「树」
用数组实现就是「堆」,因为「堆」是一个完全二叉树,用数组存储不需要节点指针,操作也比较简单;
用链表实现就是很常⻅的那种「树」,因为不一定是完全二叉树,所以不适合用数组存储。
为此,在这种链表「树」结构之上,又衍生出各种巧妙的设计,比如二叉搜索树、AVL 树、红黑树、区间树、B 树

Redis 数据库的朋友可能也知道,Redis 提供列表、字符串、集合等等几种常用数据结构,但是对于每
种数据结构,底层的存储方式都至少有两种,以便于根据存储数据的实际情况使用合适的存储方式

*数组由于是紧凑连续存储,可以随机访问,通过索引快速找到对应元素,而且相对节约存储空间。但正因为连
续存储,内存空间必须一次性分配够,所以说数组如果要扩容,需要重新分配一块更大的空间,再把数据全
部复制过去,时间复杂度 O(N);而且你如果想在数组中间进行插入和删除,每次必须搬移后面的所有数据以
保持连续,时间复杂度 O(N)。

*链表因为元素不连续,而是靠指针指向下一个元素的位置,所以不存在数组的扩容问题;如果知道某一元素
的前驱和后驱,操作指针即可删除该元素或者插入新元素,时间复杂度 O(1)。但是正因为存储空间不连续,
你无法根据一个索引算出对应元素的地址,所以不能随机访问;而且由于每个元素必须存储指向前后元素位
置的指针,会消耗相对更多的储存空间
二、数据结构的基本操作
基本操作无非遍历 + 访问,再具体一点就是:增删查改 它们存在的目的都是在不同的应用场景,尽可能高效地增删查改
各种数据结构的遍历 + 访问无非两种形式:线性的和非线性的
线性就是 for/while 迭代为代表,非线性就是递归为代表
1.数组典型的线性迭代结构
只要涉及递归,都可以抽象成二叉树的问题。
写递归算法的关键是要明确函数的「定义」是什么,
然后相信这个定义,利用这个定义推导最终结果,绝不要试图跳入递归。
从整体到细节,自顶向下,从抽象到具体的框架思维是通用的,不只是学习数据结构和算法,学习其他任何
知识都是高效的
在 C++ 中,数组参数通常需要传入数组的大小(size),因为 C++ 不像 Java 那样能自动获取数组的长度。
通过传递数组的大小 size,我们可以迭代访问数组中的每个元素。
数组遍历框架,典型的线性迭代结构:

void traverse(int arr[], int size) {for (int i = 0; i < size; i++) {// 迭代访问 arr[i]}
}
现代 C++,并且 std::vector 会自动管理数组的大小。
#include <vector>void traverse(const std::vector<int>& arr) {for (int i = 0; i < arr.size(); i++) {// 迭代访问 arr[i]}
}
//2.链表遍历框架
/* 基本的单链表节点 */
class ListNode {
public:int val; // 当前节点的值ListNode* next; // 下一个节点ListNode(int value) : val(value), next(nullptr) {}
};
//迭代
void traverse(ListNode* head) { // 头节点for (ListNode* p = head; p != nullptr; p = p->next) {// 迭代访问 p->val}
}//递归void traverse(ListNode* head) {if (head == nullptr) return;// 递归访问 head->valtraverse(head->next);
}
//3.二叉树遍历框架,典型的非线性递归遍历结构
/* 基本的二叉树节点 */
class TreeNode {
public:int val;TreeNode* left;TreeNode* right;TreeNode(int value) : val(value), left(nullptr), right(nullptr) {}
};void traverse(TreeNode* root) { // 根节点if (root == nullptr) return; // 基本情况// 访问 root->valtraverse(root->left); // 左节点traverse(root->right); // 右节点
} 
 /* 基本的 N 叉树节点 */
N 叉树的遍历又可以扩展为图的遍历,因为图就是好几 N 叉棵树的结合体。你说图是可能出现环的?这个很
好办,用个布尔数组 visited 做标记就行了
class NTreeNode {
public:int val;std::vector<NTreeNode*> children;NTreeNode(int value) : val(value) {}
};void traverse(NTreeNode* root) {if (root == nullptr) return; // 基本情况// 访问 root->valfor (NTreeNode* child : root->children) {traverse(child); // 递归访问每个子节点}
}

http://www.mrgr.cn/news/65998.html

相关文章:

  • 「C/C++」C/C++标准库 之 #include<cstdlib> 通用工具函数库
  • gRPC-拦截器
  • 关于Linux系统调试和性能优化技巧有哪些?
  • 软件设计师-上午题-16 算法(4-5分)
  • 项目一:使用 Spring + SpringMVC + Mybatis + lombok 实现网络五子棋
  • ECMAScript 新手指南教程
  • Python详细实现埃拉托斯特尼素数筛法(Sieve of Eratosthenes)
  • 人工智能学习--XGBoost算法
  • AI信息速递 20241105
  • flink 内存配置(一):设置Flink进程内存
  • 利索能及——免费专利检索平台,助力全球创新者获取知识产权保护
  • 正在进行中人生之超凡将来,光明将来的逐步建立和尝试实践以及验证卦象案例集合树库(Book)例1工期卦-雷泽归妹变震为雷
  • aosp安卓15新特性dump的wms窗口层级树优化的更加美观
  • 使用 Nginx 部署 Python 项目
  • 压缩机排气保证曲线的解读
  • 如何利用AI分析上市企业财报
  • yolo系列各种环境配置运行
  • 【算法】【优选算法】双指针(下)
  • h5web浏览器获取腾讯地图经纬度
  • 七款超好用主流图纸加密软件推荐|2024图纸加密软件最佳选择!
  • xlwings通过数字索引(i,j)读取单元格数据的方法
  • 【comfyui教程】ComfyUI 完全入门:ControlNet 使用教程
  • 第二届全国高校软件测试开发教育峰会在韩山师范学院隆重举办!
  • 微服务架构面试内容整理-Ribbon
  • 正式挑战谷歌,OpenAI 全面发布 ChatGPT Search 搜索引擎,将人人免费使用
  • 内衣洗衣机哪个牌子好用?5款高评分内衣洗衣机年终测评