数据结构基础(基于c++)

数据结构基础(基于c++)

文章目录

  • 数据结构基础(基于c++)
    • 前言
      • 1. 递归、迭代、时间复杂度、空间复杂度
      • 2. 数据结构
    • 数组与链表
      • 1. 数组
      • 2. 链表
      • 3. 动态数组
      • 4. 数组与链表对比

前言

参考资料:Hello 算法 (hello-algo.com)

1 2

1. 递归、迭代、时间复杂度、空间复杂度

递归

使用迭代模拟递归

/* 使用迭代模拟递归 */
int forLoopRecur(int n) {// 使用一个显式的栈来模拟系统调用栈stack<int> stack;int res = 0;// 递:递归调用for (int i = n; i > 0; i--) {// 通过“入栈操作”模拟“递”stack.push(i);}// 归:返回结果while (!stack.empty()) {// 通过“出栈操作”模拟“归”res += stack.top();stack.pop();}// res = 1+2+3+...+nreturn res;
}

常见时间复杂度例子:常见时间复杂度类型

常见空间复杂度例子:常见空间复杂度类型

1、常数阶:常量、变量、对象
2、线性阶:数组、链表、栈、队列
3、平方阶:矩阵、图
4、指数阶:二叉树(满二叉树)
5、对数阶:分治算法

递归函数一分为二时,时间复杂度为O(2n), 例子:func(n-1)+func(n-2)

递归函数逐层减半时,时间复杂度为O(log2n),例子:func(n/2)

主流排序算法的时间复杂度通常为 𝑂(𝑛log⁡𝑛) ,例如快速排序、归并排序、堆排序等。

笔记

// 使用系统时间生成随机种子unsigned seed = chrono::system_clock::now().time_since_epoch().count();
// 随机打乱数组元素shuffle(nums.begin(), nums.end(), default_random_engine(seed));
//to_string()函数map[i] = to_string(i);

2. 数据结构

64位计算机数据类型大小(Java):

3
  • C 和 C++ 未明确规定基本数据类型的大小,而因实现和平台各异。上表遵循 LP64 数据模型,其用于包括 Linux 和 macOS 在内的 Unix 64 位操作系统。
  • 字符 char 的大小在 C 和 C++ 中为 1 字节,在大多数编程语言中取决于特定的字符编码方法,详见“字符编码”章节。
  • 即使表示布尔量仅需 1 位(0 或 1),它在内存中通常也存储为 1 字节。这是因为现代计算机 CPU 通常将 1 字节作为最小寻址内存单元。

内存对齐

对齐规则:

  1. 第一个成员在与结构体偏移量为0的地址处

  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍地址

    对齐数 = 编译器默认的对齐数与该成员大小的较小值

  3. 结构体总大小为最大对齐数(每个成员都有一个对齐数)的整数倍

    到底为什么要内存对齐?_哔哩哔哩_bilibili

    (含字幕)C++ 让你不再害怕内存和指针 其一_哔哩哔哩_bilibili

    【C++面试100问】第二十九问:请详细讲讲C和C++中的内存分配方式_哔哩哔哩_bilibili

    4.4 内存与缓存 * - Hello 算法 (hello-algo.com)

数字是以“补码”的形式存储在计算机中的

计算机内部的硬件电路主要是基于加法运算设计的

问题:哈希冲突、红黑树

数组与链表

1. 数组

4

索引本质上是内存地址的偏移量

访问:在数组中访问元素非常高效,我们可以在 𝑂(1) 时间内随机访问数组中的任意一个元素。(随机访问

插入:如果想在数组中间插入一个元素,则需要将该元素之后的所有元素都向后移动一位,之后再把元素赋值给该索引。

/* 在数组的索引 index 处插入元素 num */
void insert(int *nums, int size, int num, int index) {// 把索引 index 以及之后的所有元素向后移动一位for (int i = size - 1; i > index; i--) {nums[i] = nums[i - 1];}// 将 num 赋给 index 处的元素nums[index] = num;
}

删除:若想删除索引 𝑖 处的元素,则需要把索引 𝑖 之后的元素都向前移动一位。删除元素完成后,原先末尾的元素变得“无意义”了,所以我们无须特意去修改它。

/* 删除索引 index 处的元素 */
void remove(int *nums, int size, int index) {// 把索引 index 之后的所有元素向前移动一位for (int i = index; i < size - 1; i++) {nums[i] = nums[i + 1];}
}

数组的优缺点

数组存储在连续的内存空间内,且元素类型相同。这种做法包含丰富的先验信息,系统可以利用这些信息来优化数据结构的操作效率。

  • 空间效率高:数组为数据分配了连续的内存块,无须额外的结构开销。
  • 支持随机访问:数组允许在 𝑂(1) 时间内访问任何元素。
  • 缓存局部性:当访问数组元素时,计算机不仅会加载它,还会缓存其周围的其他数据,从而借助高速缓存来提升后续操作的执行速度。

连续空间存储是一把双刃剑,其存在以下局限性。

  • 插入与删除效率低:当数组中元素较多时,插入与删除操作需要移动大量的元素。
  • 长度不可变:数组在初始化后长度就固定了,扩容数组需要将所有数据复制到新数组,开销很大。
  • 空间浪费:如果数组分配的大小超过实际所需,那么多余的空间就被浪费了。

应用:数组典型应用

2. 链表

5 6

链表节点 ListNode 除了包含值,还需额外保存一个引用(指针)。因此在相同数据量下,链表比数组占用更多的内存空间

通常将头节点当作链表的代称

插入:假设我们想在相邻的两个节点 n0n1 之间插入一个新节点 P则只需改变两个节点引用(指针)即可,时间复杂度为 𝑂(1) 。

/* 在链表的节点 n0 之后插入节点 P */
void insert(ListNode *n0, ListNode *P) {ListNode *n1 = n0->next;P->next = n1;n0->next = P;
}

删除:在链表中删除节点也非常方便,只需改变一个节点的引用(指针)即可

/* 删除链表的节点 n0 之后的首个节点 */
void remove(ListNode *n0) {if (n0->next == nullptr)return;// n0 -> P -> n1ListNode *P = n0->next;ListNode *n1 = P->next;n0->next = n1;// 释放内存delete P;
}

访问:

/* 访问链表中索引为 index 的节点 */
ListNode *access(ListNode *head, int index) {for (int i = 0; i < index; i++) {if (head == nullptr)return nullptr;head = head->next;}return head;
}

查找:

/* 在链表中查找值为 target 的首个节点 */
int find(ListNode *head, int target) {int index = 0;while (head != nullptr) {if (head->val == target)return index;head = head->next;index++;}return -1;
}

应用:链表经典应用

3. 动态数组

vector

访问:用索引进行访问

插入与删除:

/* 清空列表 */
nums.clear();/* 在尾部添加元素,时间复杂度O(1) */
nums.push_back(1);
nums.push_back(3);
nums.push_back(2);
nums.push_back(5);
nums.push_back(4);/* 在中间插入元素,时间复杂度O(n) */
nums.insert(nums.begin() + 3, 6);  // 在索引 3 处插入数字 6,insert是在前一个位置插入元素/* 删除元素,时间复杂度O(n) */
nums.erase(nums.begin() + 3);      // 删除索引 3 处的元素

拼接:

/* 拼接两个列表 */
vector<int> nums1 = { 6, 8, 7, 10, 9 };
// 将列表 nums1 拼接到 nums 之后
nums.insert(nums.end(), nums1.begin(), nums1.end());

排序:

/* 排序列表 */
sort(nums.begin(), nums.end());  // 排序后,列表元素从小到大排列

用数组实现动态数组:用数组实现动态数组

4. 数组与链表对比

7

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

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

相关文章

假期已结束,大家都开始上班了吗

千行赏金APP&#xff1a;一站式悬赏任务平台详解 一、功能特点 千行赏金APP&#xff0c;作为一个综合性的悬赏任务平台&#xff0c;其功能特点突出&#xff0c;为用户提供了丰富的体验。首先&#xff0c;用户可以在平台上发布各类任务&#xff0c;如填写问卷、参与调研、试玩游…

MySQL高性能(MySQL锁)

MySQL性能系列 MySQL锁 前言1. 死锁机制2. 思维导图与锁划分介绍3. 粒度划分锁3.1. 全局锁3.2. 页级锁&#xff08;Page-level locking&#xff09;3.3. 表级锁&#xff08;Tables-level lock&#xff09;○ 共享锁&#xff08;表级&#xff09;○ 排他锁&#xff08;表级&…

安徽京准-时间源设备(时间源服务器)助力医疗信息化建设

安徽京准-时间源设备&#xff08;时间源服务器&#xff09;助力医疗信息化建设 安徽京准-时间源设备&#xff08;时间源服务器&#xff09;助力医疗信息化建设 医院时钟系统主要为全医院提供提供统一的准确时间&#xff0c;其主要作用是为整个医院的计算机系统及呼叫系统、BA系…

【perl】环境搭建

1、Vscode Strawberry Perl 此过程与tcl环境搭建很类似&#xff0c;请参考我的这篇文章&#xff1a; 【vscode】 与 【tclsh】 联合搭建tcl开发环境_tclsh软件-CSDN博客 perl语言的解释器可以选择&#xff0c;strawberry perl。Strawberry Perl for Windows - Releases。 …

如何在Linux虚拟机服务器上配置和部署Java项目?

在Linux虚拟机上配置和部署Java项目&#xff0c;通常涉及以下步骤&#xff1a; 1. 准备Linux虚拟机 选择合适的Linux发行版 &#xff1a;根据项目需求和个人熟悉程度&#xff0c;选择如Ubuntu LTS、CentOS Stream或Debian等发行版。 安装虚拟机软件 &#xff1a;在宿主机&#…

VS 2019 @ Win10 C++ MFC 安装实践

1 打开卸载窗口&#xff1a; 选择Windwos 卸载 &#xff0c;笔者有多个版本&#xff0c;选择VS1019 现在算正式打开了VS 1019的卸载&#xff0c;注意千万别点确认&#xff0c;点击&#xff0c;取消&#xff0c;进入安装配置 点击&#xff0c;取消后&#xff0c;进入VS 的安装配…

[图解]建模相关的基础知识-08

1 00:00:01,650 --> 00:00:04,950 如果说&#xff0c;A乘BB乘A的话 2 00:00:06,350 --> 00:00:07,140 意味着什么 3 00:00:07,560 --> 00:00:08,420 A就等于B了 4 00:00:09,500 --> 00:00:10,680 只有两个相等 5 00:00:10,690 --> 00:00:13,360 它们的笛卡尔…

旅游卡免费旅游的使用条件有哪些?

随着旅游业的繁荣发展和消费者需求的多样化&#xff0c;各种旅游促销活动层出不穷。其中&#xff0c;旅游卡免费旅游以其独特的吸引力&#xff0c;成为了不少消费者关注的焦点。 然而&#xff0c;正如任何促销活动都有其限制条件一样&#xff0c;旅游卡免费旅游也不例外。在享…

计算机专业英语Computer English

计算机专业英语 Computer English 高等学校计算机英语教材 Contents 目录 Part One Computer hardware and software 计算机硬件和软件----------盖金曙 生家峰 Unit 1 the History of Computers计算机的历史 Unit 2 Computer System计算机系统 Unit 3 Di…

docker回顾--docker compose详细解释,安装,与常用命令

文章目录 Docker compose简介什么是Docker compose核心概念优势 安装常用命令总结 Docker compose简介 什么是Docker compose Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。它使得开发者可以使用一个单独的 YAML 文件来定义应用所需的所有服务、网络和卷&a…

行为树BehaviorTree

主要依托于BehaviorTree.CPP进行介绍。 1 基本概念 1.1 是什么与用来做什么 官网 https://www.behaviortree.dev/docs/learn-the-basics/BT_basics Unlike a Finite State Machine, a behavior Tree is a tree of hierarchical nodes that controls the flow of execution o…

探索正则表达式的神奇魅力

正则表达式 正则表达式&#xff0c;如同一位技艺精湛的艺术家&#xff0c;能够以极致的精准和优雅&#xff0c;雕刻出你想要的文本形态。它的魅力在于其简练而灵活的语法&#xff0c;让你得以轻松地在庞杂的文字丛林中捕捉目标。 无论是验证数据格式的合法性、从复杂文本中提…

AWS概述

AWS概述EMR Serverless Aamzon Web Services提供了一系列全球范围的云产品&#xff0c;包括计算、存储、数据库、分析、网络、移动、开发工具、管理工具、IoT、安全和企业应用&#xff1a;按需交付、及时可用、采用随用随付的定价模式。你可以畅享200多种服务&#xff0c;从数据…

乡村振兴的乡村基础设施建设:完善基础设施,提升乡村生活品质,打造宜居宜业的美丽乡村

摘要&#xff1a;乡村振兴是新时代中国特色社会主义“三农”工作的重要内容&#xff0c;而乡村基础设施建设作为乡村振兴的基石&#xff0c;对于提升乡村生活品质、打造宜居宜业的美丽乡村具有至关重要的意义。本文从乡村基础设施建设的必要性出发&#xff0c;分析了当前乡村基…

用GAN网络生成彩票号码

本文将详细解析如何使用生成对抗网络(GAN)来生成彩票号码。我们将介绍代码的每个部分,并给出详细注释,帮助读者理解整个过程。效果如下: 导入依赖 首先,我们需要导入所需的库。 import numpy as np import pandas as pd import torch import torch.nn as nn import t…

区分POJO、DTO、DO、VO、BO、PO、Entity

简述&#xff1a; VO 用于后端向前端传输数据&#xff1b; DTO用于前端向后端传输数据&#xff1b; BO用于微服务之间传输数据&#xff1b; PO等同于Entity&#xff0c;DO是Entity的一种&#xff0c;三者用于表示数据库的一条记录&#xff0c;通常用Entity。 &#xff08;…

14年后 苹果终于推出iPad原生计算器应用

迄今为止&#xff0c;在WWDC 2024大会上&#xff0c;新增的计算器应用获得了最热烈的掌声。iOS 官方计算器应用程序终于要登陆大屏幕了。该功能利用额外的屏幕空间带来了公司无法在 iPhone 上实现的新功能。其中最大的亮点是新增了"数学笔记"功能。新增的功能可以帮你…

酶酵母展示技术简介

酵母展示技术&#xff08;Yeast Display Technology&#xff09;是指将酶序列/酶突变文库序列与凝集素Aga2p融合表达&#xff0c;Aga2p蛋白亚基通过两个二硫键与固定在酵母细胞壁上的Aga1p 蛋白亚基结合&#xff08;即载体蛋白将蛋白酶&#xff08;带有特定标签&#xff09;以活…

黑豹程序员 堆和栈

简单变量及作用域 main()   int x1; show ()   int x2 执行步骤&#xff1a; 第1步&#xff1a;main()函数是程序入口&#xff0c;JVM先执行&#xff0c;在栈内存中开辟一个空间&#xff0c;存放int类型变量x&#xff0c;同时附值1。 第2步&#xff1a;JVM执行show()函…

c++/c中野指针和悬空指针的示例

目录 一、野指针的概念 二、野指针示例 三、悬空指针的概念 四、悬空指针示例 1.指针释放后未置空 2.返回栈内存地址的指针 一、野指针的概念 野指针是指尚未初始化的指针&#xff0c;它指向的地址是未知的、不确定的、随机的。这种指针在使用时可能导致程序崩溃、数据损…