三哥数据结构

一. 目录:

涉及:

抽象数据类型ADT(abstract data type),列表 list,数组 array,链表 linked list,栈 stack,队列queue,树 tree,图表 graph

研究内容:

逻辑视图 Logical view,操作 operation,操作成本 cost of operations(主要是时间方面),如何实现 imprementation

二. ADT

list 是相同类型对象的集合,可以将 list 定义为一个 ADT。

1. 静态列表

可以实现以下功能:

(1)储存给定数据类型的元素的给定数字(列表中元素数量不会改变)

(2)书写/更改任何位置的元素

(3)读取。。。

如何实现呢?使用数组

对应如图所示

2. 动态列表:

实现功能:

(1)如果列表没用元素,则列表为空,其大小为0,sige 0

(2)在列表中任何位置插入元素

(3)。。。删除。。。

(4)计算列表的元素数量

(5)读/更改。。

(6)指定数据类型(int 等)

如何实现:

使用Int 来定义一个数组,如上图所示。

定义对应的max size,

如果列表为空,则可以初始化变量 / 使用int end =-1,将变量设置为-1,因为最低的索引是0,所以不存在。

如果数组需要变大,变大多大合适呢?

变大一倍。

针对于 access等操作,时间复杂度如图,但是如何更高效?则使用链表 Linked lists。

三. linked list:

1. 为何从list 转到 linked list

首先了解下数组List的储存原理。

对于内存 memory 如图,存在一个内存管理器 memory manager 来分配内存,对于程序员需要跟 manager 申请4个内存空间来存贮整型 int x,如图所示。

之后,如果申请一个整型数组 list,如 int A[4],则需要分配如下16个内存空间。

但是需要注意的是,因为之前已经申请过int x存储了,所以对应List 的 A[4] 的后面被 x 堵死了,所以如果想扩大数组 A,则需要重新申请内存,并且把所有的元素进行复制。

但是由于扩大多少内存空间,程序员也不知道,所以依旧会存在内存不够用或者内存过大导致浪费的情况,所以如何更加高效?引出 linked list 链表。

链表的内存是分散储存的,但是如果不是连续的,如何依次读取呢?所以就引出链表的储存特点:每个元素储存时候存在两个方面:一部分储存元素本身(整型变量),另一部分存储下一个元素的地址(指针变量)。

因为最后一块没有下一个元素,所以它的第二个部分存储为0,0为无效地址,因此也可以用这个标记是列表的末尾。

同时整型和指针变量都占据四个字节。

总之,linked list 的数据结构就是将节点在不同的地址进行储存,并且每个节点都指向下一个节点 的位置。

其中第一个节点,称为 head node,我们始终保持的关于列表的唯一信息就是头节点的地址,通过其可以访问完整的列表,这也是读取列表的唯一方法,当然遍历到最后一个节点的时间复杂度为O(n)。

最后一个节点的地址是 null 或者0,意思是不指向任何节点。

如果在末节点想添加一个3,则需要先创建一个节点,分配它的内存地址,然后改之前的末节点的指向地址,就可以添加了,相比于 List 大幅度提高效率。

当然在中间插入的时候,时间复杂度也是O(n)。

2. array VS linked list

对比数组和链表,以下分为两列进行对比:

(1)首先是访问元素的时间成本:

由于array 是连续地储存在内存当中,所以对应的时间成本是O(1).

而 linked list 是每个模块(node)分别储存在不同地方,所以对应的时间成本为O(n)

因此,如果有需要始终访问列表中元素的需求时候,选用数组 array 比较好。

(2)内存需求/内存使用:

array 所占内存要求是连续的,且是固定大小的,一旦数组别填满需要扩大,则需要重新分配内存并进行复制

而 linked list 的内存储存是分开的,但是每个node 所占字节是比 array 大,比如说整型Int ,linked list 每个node 所占内存为8,而 array 的每个node 则是4,这也是一个区别。

(3)在其中插入元素的时间成本:

这个需要分情况讨论:

a. 在头节点插入元素:针对于array,需要每一个节点都向后移动,所以是O(n),而对于 Linked list ,则是O(1)。

b. 如果在末尾插入元素:针对于array,如果数组没有被填满,则是O(1),如果数组被填满了,则是O(n),对于linked list,因为只能从头开始找,一直找到end node,所以时间成本为O(n)。

c. 如果是在中间插入元素:针对于array,假如在中间位置进行插入,则需要移动后面一半的元素位置,对应时间成本为O(2/n),可以视为O(n)。针对于linked list,同理需要找到这个位置的所有前面的元素地址,所以可以视为O(n)。

同理于删除元素。

(4)谁更容易用:

3. imprementation in CPP:

(1)CPP基础:

C++基础——C++ 变量类型_c++定义变量时用sword-CSDN博客

在C++中,extern关键字用于指明变量或函数的声明是外部链接的,这意味着它们的定义在当前的编译单元之外。使用extern声明的变量或函数可以在多个不同的源文件中访问,但它们只能被定义一次。

具体来说:

  1. 变量声明:当你在多个文件中使用同一个全局变量时,你可以在一个文件中定义这个变量,并在其他文件中使用extern来声明这个变量。这样,所有文件中使用这个变量的值都是相同的。

  2. 函数声明:如果你在一个文件中定义了一个函数,并希望在其他文件中调用它,你可以在其他文件中使用extern来声明这个函数。这告诉编译器该函数的定义在其他地方。

// file1.cpp
int a = 10;  // 定义变量a
int b = 20;  // 定义变量b

// file2.cpp
extern int a;  // 声明变量a,它在file1.cpp中定义
extern int b;  // 声明变量b,它在file1.cpp中定义

void printAB() {
    std::cout << "a = " << a << ", b = " << b << std::endl;
}

在这个例子中:

  • file1.cpp 中定义了两个全局变量 a 和 b
  • file2.cpp 中使用 extern 声明了这两个变量,表明它们在其他地方定义。然后,printAB 函数可以访问这两个变量并打印它们的值。

注意:

  • 变量或函数只能在一个文件中定义,但可以在多个文件中声明
  • 如果没有使用 extern 声明,编译器会默认在当前文件中寻找变量或函数的定义,如果没有找到,会导致链接错误。

extern关键字在大型项目中非常有用,它允许在不同的文件之间共享全局变量和函数

C++ 中的内联函数(Inline Function)是一种请求编译器尽可能在每个调用点上“内联展开”该函数的特殊函数。内联展开意味着编译器会在每个调用该函数的地方直接插入(或替换)该函数的代码体,而不是像通常那样进行函数调用(即生成调用指令、保存调用状态、跳转到函数体执行、恢复调用状态并返回)。这样做的好处是可以减少函数调用的开销,特别是对于那些体积小、调用频繁的函数,可以显著提高程序的执行效率。

「C++系列」函数/内置函数_c++ 内置函数-CSDN博客

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值