数据结构入门RT_5_31

计算机小菜狗的数据结构学习之路上狂奔:

持续更新中~~~~~

> RT_5_31   

> 计算机数据结构的学习内容:   

> 1.基本概念   

- 数据结构:数据元素之间存在的特定关系,以及这些关系在计算机中的表示和实现。   
- 数据类型:数据的种类以及在这些数据上可以进行的操作。   
- 抽象数据类型(ADT):定义了一组值以及这组值上的一组操作,但不关心这些操作的具体实现。   
   
> 2.算法分析   

- 时间复杂度:评估算法执行时间随数据规模增长的变化趋势。   
- 空间复杂度:评估算法执行过程中所需存储空间的大小。   
- 稳定性、正确性等其他算法评价指标。   
   
> 3.线性数据结构   

- 数组(Array):具有相同数据类型的元素组成的固定大小的连续存储空间。   
- 链表(Linked List):由节点组成,每个节点包含数据和指向下一个节点的指针。链表包括单向链表、双向链表和循环链表等。   
- 栈(Stack):后进先出(LIFO)的数据结构,支持主要操作有push(压栈)、pop(弹栈)、peek(查看栈顶元素)等。   
- 队列(Queue):先进先出(FIFO)的数据结构,支持主要操作有enqueue(入队)、dequeue(出队)、front(查看队首元素)等。   
   
> 4.树形数据结构   

- 树(Tree):包含节点和边的集合,其中每个节点都有一个父节点(除了根节点)和零个或多个子节点。   
- 二叉树(Binary Tree):每个节点最多有两个子节点的树。   
- 二叉搜索树(Binary Search Tree, BST):在二叉树的基础上,满足左子树所有节点的值小于根节点,右子树所有节点的值大于根节点的条件。   
- 平衡二叉树(AVL树、红黑树等):通过平衡因子和调整策略来保持树的平衡,以避免树形退化为链表。   
- 堆(Heap):特殊的树形数据结构,通常用于实现优先队列,如最大堆和最小堆。   
   
> 5.图形数据结构   

- 图(Graph):由顶点和边(或弧)组成的集合,用于表示对象之间的关系。   
- 无向图(Undirected Graph):图中的边没有方向的图。   
- 有向图(Directed Graph):图中的边有方向的图。   
- 邻接矩阵(Adjacency Matrix):表示图中顶点之间相邻关系的二维数组。   
- 邻接表(Adjacency List):表示图中每个顶点相邻顶点的链表。   
   
> 6.特殊数据结构   

- 散列表(Hash Table):基于哈希函数实现快速查找的数据结构。   
- 跳表(Skip List):一种随机化的数据结构,支持高效的查找、插入和删除操作。   
- 并查集(Disjoint Set):一种处理一些不交集(Disjoint Sets)的合并及查询问题的数据结构。   
- 线段树(Segment Tree):用于维护区间信息的一种数据结构。   
- 树状数组(Binary Indexed Tree):用于解决数组部分和问题的一种数据结构。   
   
> 7.查找与排序   

- 查找算法:顺序查找、二分查找、哈希查找、插值查找、斐波那契查找等。   
- 排序算法:冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、堆排序、计数排序、桶排序、基数排序等。   
   
> 8.数据结构的应用   

- 数据结构在操作系统、数据库系统、编译原理、图形学、人工智能等领域的应用。   
- 数据结构在解决实际问题时的应用,如最短路径问题、最小生成树问题、网络流问题等。   
   
以上大体就是数据结构的整体的知识框架,前六章基本上是概念篇,后两章是应用篇   
接下来我们就逐章展开分析学习。   
> 基本概念   

> 计算机中的计算   

|                       |                                                                                                                                                                                                                                                                                                                                                      计算机 |                                                                                                                                                                                                                            数学 |
|:----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|                数值表示方式 |                                                                                                                                                                                                                                                                                     *计算机内部所有的计算都是基于二进制的,因为计算机只识别0和1两种状态。这种二进制表示方式使得计算机能够高效地进行逻辑运算和数据处理。* |                                                                                                                                                                                  *通常在十进制(或其他进制,如二进制、八进制、十六进制等)下进行,但最常见的是十进制。* |
|               运算方式和范围 |                                                                                                                                                                                                                                                                       *除了基本的四则运算外,还包括逻辑运算、位运算等。在计算机中,所有的数据都被视为二进制位(bit)的集合,因此计算机的计算更多地关注于这些位之间的逻辑关系和运算。* |                                                                                                                                                   *包括四则运算(加、减、乘、除)、乘方、开方、对数、三角函数等多种运算方式。数学计算的范围非常广泛,包括实数、复数、矩阵、向量等不同类型的数学对象。* |
|                 精度和误差 |                                                                                                                                                                                                                                                                         *由于计算机的字长和表示方式的限制,计算结果可能存在精度损失和舍入误差。此外,计算机在进行浮点数运算时,由于浮点数的表示方式和运算规则,可能会产生较大的误差。* |                                                                                                                                                   *理论上可以达到无限精度,但实际计算中由于计算工具的限制(如纸笔计算、计算器、计算机等)和计算方法的选择(如近似算法、迭代算法等),可能会引入误差。* |
|                复杂性和效率 |                                                                                                                                                                                                                                                                       *复杂性不仅体现在问题的规模和计算方法上,还受到计算机硬件和操作系统的影响。在计算机中,选择合适的算法和数据结构、优化代码、并行计算等都是提高计算效率的重要手段。* |                                                                                                                                                                       *复杂性主要体现在问题的规模和计算方法的选择上。对于同一个问题,不同的计算方法可能导致计算复杂度的巨大差异。* |
|               可靠性和稳定性 |                                                                                                                                                                                                                                     *由于计算机系统的复杂性和各种外部因素的干扰(如硬件故障、网络延迟、病毒攻击等),计算机计算的可靠性和稳定性可能会受到影响。因此,在计算机中进行计算时,需要采取各种措施来确保计算的正确性和可靠性,如数据校验、错误处理、备份恢复等。* |                                                                                                                                                              *在理想情况下,数学计算是可靠和稳定的,但实际应用中可能会受到数据来源、计算方法、计算工具等因素的影响而产生误差或不稳定现象。* |

> 数据结构与数据元素与数据项   

- 数据结构(Data Structure):就是研究大量数据在计算机中的存储的组织形式,并定义且实现对数据相应的高效预算,以提高计算机的数据处理能力的一门科学。   
- 数据元素(Data Element):也称为结点或记录,是数据的基本单位。它通常用于描述和标识客观事物的某种属性,并在计算机程序中作为一个整体进行考虑和处理。数据元素可以用一组属性来描述其定义、标识、表示和允许值。   
- 数据项(Data Item):是数据的不可分割的最小单位,用于描述实体的某种属性。数据项可以是字母、数字或两者的组合,并通过数据类型(如逻辑的、数值的、字符的等)及数据长度来描述。   
- 数据元素是数据的基本单位,它在计算机程序中作为一个整体进行考虑和处理。数据项则是数据的不可分割的最小单位,它构成了数据元素的基础。   
   
> 逻辑结构与物理结构   

> 逻辑结构   

逻辑结构是指数据元素之间的逻辑关系,即数据元素之间的前后件关系,而与它们在计算机中的实际存储位置无关。逻辑结构是从具体问题抽象出来的数学模型,是描述数据元素之间的关系的数学方法。   
> 逻辑结构主要有以下几种类型:   

1. **集合结构**:数据元素之间除了“同属于一个集合”的关系外,别无其他关系。   
2. **线性结构**:数据元素之间存在一对一的关系。常见的线性结构有线性表、栈、队列等。   
3. **树形结构**:数据元素之间存在一对多的关系。常见的树形结构有二叉树、多叉树等。   
4. **图形结构**:数据元素之间存在多对多的关系。图形结构是一种比树形结构更复杂的非线性结构   
   
> 物理结构   

物理结构(或存储结构)是指数据的逻辑结构在计算机中的存储表示,也称为数据的存储结构。数据的物理结构是数据结构在计算机中的表示(又称映像),它包括数据元素的表示和关系的表示。   
> 物理结构主要有以下几种类型:   

1. **顺序存储结构**:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来表示。顺序存储结构的主要优点是节省存储空间,因为分配给数据的存储单元全用存放结点的数据(不考虑c/c++语言中数组需留一个位置给越界检测),结点之间的逻辑关系没有占用额外的存储空间。采用这种方法时,可实现对结点的批量存取,即按一个地址存取另一地址。   
2. **链式存储结构**:逻辑上相邻的元素在物理位置上可以不相邻,借助指示元素存储地址的指针来表示元素之间的逻辑关系。链式存储结构的主要优点是便于插入和删除操作。使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机存取的优点,同时链表由于增加了结点的指针域,空间开销比较大   
   
> 算法与程序   

> 算法(Algorithm)   

算法是解决问题的一系列明确指示的步骤,通常包含一组规则,这些规则定义了用于解决问题的操作序列。算法可以是简单的,也可以是复杂的,但它们都具有以下特点:   
- **明确性**:算法的每一步都必须是明确和清晰的,不能有歧义。   
- **有限性**:算法必须包含有限数量的步骤,并且每个步骤都必须在有限的时间内完成。   
- **无歧义性**:算法中的每一个步骤都应该有明确的意义,并且不会导致不同的解释。   
- **通用性**:算法可以应用于多种不同的问题,而不仅仅是针对某个特定问题的解决方案。   
   
> 程序(Program)   

程序是计算机可以理解和执行的指令集合。它是用某种编程语言编写的,并可以被计算机解释或编译为机器语言来执行。程序通常包括数据结构、算法和变量等组成部分。   
###    
> 算法效率与程序性能分析   

> 算法效率   

算法效率是指算法执行所需的时间和资源。一个高效的算法能够在较短的时间内完成任务,使用较少的内存和处理器资源。算法效率的重要性体现在以下几个方面:   
1. **用户体验**:快速响应的应用程序通常会给用户留下更好的体验,而慢速应用程序可能会导致用户流失。   
2. **资源利用**:高效的算法可以节省计算机资源,包括处理器时间和内存,从而降低成本。   
3. **大规模数据处理**:在处理大规模数据集时,高效的算法可以显著减少处理时间,提高工作效率。   
4. **可伸缩性**:高效的算法更容易扩展到大规模的应用程序和系统中,而不会导致性能下降。   
   
衡量算法效率的关键指标包括时间复杂度和空间复杂度。时间复杂度表示算法执行所需时间随输入规模增长的趋势,如O(1)、O(log n)、O(n)、O(nlog n)和O(n^2)等。空间复杂度则衡量算法所需内存空间随输入规模增长的趋势。   
> 程序性能   

程序性能分析是计算机程序的一种重要的性能分析方法,用于检查程序中存在的性能问题以及程序运行时性能表现。其主要目的是改善程序的性能,提高程序的执行效率。程序性能分析可以分为静态性能分析和动态性能分析两类:   
1. **静态性能分析**:基于程序代码的性能分析方法,主要目的是通过分析源代码结构,预估程序的性能指标,找出可能引起性能问题的原因,从而提供优化建议。   
2. **动态性能分析**:基于程序运行时的性能分析方法,主要是通过收集、分析程序的运行时性能指标(如CPU使用率、内存使用情况、线程创建次数等),找出可能影响性能的因素,从而提供优化建议。   
   
> C++中的vector   

C++中,`vector` 是一个动态数组,它可以根据需要自动增长或缩小其大小。`vector` 是C++标准模板库(STL)的一部分,它提供了许多方便的方法来操作元素,如添加、删除、访问和遍历。   
> 一个简单的示例,展示如何使用vector   

#include <iostream>  

#include <vector>  

using namespace std;

int main() {  

    // 创建一个空的int类型的vector  

    vector<int> myVector;  

  

    // 向vector中添加元素  

    myVector.push_back(1);  

    myVector.push_back(2);  

    myVector.push_back(3);  

  

    // 查看vector的大小  

    cout << "Size of vector: " << myVector.size() << endl;  

  

    // 访问vector中的元素  

    cout << "Element at index 0: " << myVector[0] << endl;  

    cout << "Element at index 1: " << myVector[1] << endl;  

  

    // 使用at方法访问元素(会进行边界检查)  

    cout << "Element at index 2: " << myVector.at(2) << endl;  

  

    // 在vector的末尾添加多个元素  

    myVector.insert(myVector.end(), 4);  

    myVector.insert(myVector.end(), 5, 6); // 插入5个值为6的元素  

  

    // 遍历vector中的元素  

    for (int i = 0; i < myVector.size(); ++i) {  

        cout << "Element " << i << ": " << myVector[i] << endl;  

    }  

  

    // 使用迭代器遍历vector中的元素  

    for (vector<int>::iterator it = myVector.begin(); it != myVector.end(); ++it) {  

        cout << "Element: " << *it << endl;  

    }  

  

    // 使用C++11的基于范围的for循环遍历vector中的元素  

    for (int element : myVector) {  

        cout << "Element: " << element << endl;  

    }  

  

    // 删除vector中的元素  

    myVector.erase(myVector.begin() + 2); // 删除索引为2的元素  

  

    // 清空vector  

    myVector.clear();  

  

    // 再次检查vector是否为空  

    if (myVector.empty()) {  

        cout << "Vector is empty now." << endl;  

    }  

  

    return 0;  

}


> C++中的iterator迭代器与指针的区别   

在C++中,迭代器(iterator)和指针(pointer)都是用于访问和操作容器(如 `std::vector`、 `std::list` 等)或数组中的元素的重要工具,但它们之间存在一些关键的区别。这些区别主要体现在以下几个方面:   
1. **通用性和抽象性**:   
    - 迭代器是C++标准库中的一个概念,它为不同的容器类型提供了统一的接口,使得我们可以用相同的方式遍历和操作不同的容器。迭代器是这些容器提供的一种内部实现的抽象,对于用户来说,它们看起来就像是指向容器中元素的指针。   
    - 指针是C和C++语言中的一个原生特性,它直接关联到内存地址,并且可以直接进行算术运算。指针可以指向任何类型的数据,并且可以通过解引用操作来访问指针所指向的数据。   
2. **类型安全性**:   
    - 迭代器是类型安全的,它们被设计为只能用于特定的容器类型。迭代器通常包含有关它们所关联的容器和当前位置的信息,这使得编译器能够在编译时检查迭代器的使用是否正确。   
    - 指针的类型安全性较低,因为它们只是内存地址的抽象。虽然C++引入了类型别名和类型转换来增强指针的类型安全性,但仍然容易出错。   
3. **功能差异**:   
    - 迭代器提供了许多有用的成员函数和操作,如 `begin()`、 `end()`、 `++`、 `--`、 `\*`、 `->` 等,这些函数和操作使得我们可以方便地遍历和操作容器中的元素。此外,迭代器还支持一些额外的操作,如 `insert` 和 `erase`,这些操作允许我们在遍历容器的同时修改容器的内容。   
    - 指针主要用于访问和操作内存中的数据。虽然指针也支持一些基本的算术运算(如加法、减法)和解引用操作,但它们的功能相对有限,并且不直接支持容器的修改操作。   
4. **适用场景**:   
    - 迭代器主要用于遍历和操作C++标准库中的容器,如 `std::vector`、 `std::list`、 `std::map` 等。这些容器提供了迭代器接口,使得我们可以使用统一的语法来访问和操作它们中的元素。   
    - 指针在C++中用于各种场景,包括访问数组元素、分配和释放内存、操作C风格的字符串等。指针还可以用于实现一些高级特性,如函数指针、动态绑定和多态等。   
5. **内存管理**:   
    - 迭代器本身并不直接管理内存。它们只是容器和元素之间的一个中介,用于访问和操作容器中的元素。迭代器的生命周期通常与容器相关联,当容器被销毁时,迭代器也会失效。   
    - 指针则直接关联到内存地址,并可以用于管理内存。在C++中,我们通常使用 `new` 和 `delete` 操作符来分配和释放动态内存,这些操作都是通过指针来完成的。指针的生命周期和内存管理需要程序员自己控制,这可能会导致一些常见的内存管理问题,如内存泄漏和悬挂指针等。   
   
需要注意的是,尽管迭代器和指针在概念和功能上有所不同,但在某些情况下,它们可以相互转换或替代。例如,对于C++标准库中的某些容器(如 `std::vector`),我们可以使用指针来直接访问容器中的元素,但这通常不是推荐的做法,因为这样做会破坏容器的封装性和类型安全性。   
  
> C++中的遍历   

遍历(Traversal)是一个通用概念,它指的是按照某种特定的顺序访问数据结构(如数组、向量、列表、树、图等)中的每一个元素或节点,并确保每个元素或节点只被访问一次。遍历的目的可能是为了查找、更新、删除元素,或者简单地为了执行某些操作。   
> 算法分析   

> 线性数据结构   

> 数组(Array)——线性表   

线性数据结构中的数组是一种最基本且广泛使用的数据结构,它允许存储一系列相同类型的元素,并且这些元素在内存中连续排列。数组的每个元素都可以通过索引(通常是整数)来访问,索引通常从0开始。   
以下是数组的一些主要特点和性质:   
1. **连续的内存空间**:数组中的元素在内存中连续排列,这意味着通过索引可以快速地找到并访问数组中的任何元素。这种连续的内存布局也是数组访问效率高的主要原因。   
2. **固定大小**:一旦数组被创建,它的大小(即可以容纳的元素数量)就固定了。如果需要存储更多的元素,可能需要重新分配一个更大的数组,并将原数组的元素复制到新数组中。这个过程可能会消耗一些时间和内存资源。   
3. **随机访问**:由于数组中的元素是连续存储的,因此可以通过索引直接访问数组中的任何元素。这种随机访问的特性使得数组在处理需要快速访问特定元素的场景时非常有效。   
4. **元素类型相同**:数组中的所有元素都必须具有相同的类型。这意味着不能在一个数组中混合存储不同类型的元素。   
5. **可迭代**:数组是可迭代的,这意味着可以使用循环结构(如for循环)来遍历数组中的所有元素。   
6. **索引范围**:数组的索引范围通常是从0开始到数组大小减1。尝试访问超出这个范围的索引可能会导致错误或异常。   
7. **初始化**:在创建数组时,可以选择是否初始化数组中的元素。如果未初始化,数组中的元素将包含垃圾值(在C/C++中)或默认值(如Java中的0或null)。   
8. **操作**:数组支持多种操作,如插入、删除、查找和修改等。但是,由于数组的大小是固定的,插入和删除操作可能会涉及元素的移动和复制,这可能会降低效率。因此,在需要频繁进行插入和删除操作的场景中,可能需要考虑使用其他数据结构(如链表)。   
   
数组在许多编程场景中都非常有用,例如存储一组有序的数字、字符串或对象等。然而,由于数组的大小是固定的,因此在处理动态数据时可能会受到限制。在这种情况下,可以考虑使用动态数组(如Java中ArrayList)或其他动态数据结构(如链表)来解决问题。   
> 链表(Linked List)   

链表(Linked List)是线性数据结构的一种,它允许动态地添加和删除元素。链表中的元素(通常称为节点)不是像数组那样在内存中连续排列,而是通过指针或引用来链接的。每个节点包含两个部分:数据部分(用于存储实际的数据)和链接部分(用于指向下一个节点)。   
以下是链表的一些主要特点和性质:   
1. **动态大小**:链表的大小可以动态地改变。这意味着可以根据需要在链表中添加或删除节点,而不需要像数组那样重新分配整个内存块。   
2. **非连续内存**:链表中的节点在内存中不是连续排列的,它们通过指针或引用来连接。这种非连续的特性使得链表能够灵活地适应不同大小的内存块。   
3. **访问方式**:链表只能从头节点开始,通过每个节点的链接部分顺序地访问下一个节点。因此,链表的访问效率不如数组高,因为无法直接通过索引访问任意位置的元素。   
4. **插入和删除**:由于链表中的节点是通过链接来连接的,因此在链表中插入或删除节点通常只需要修改相邻节点的链接即可,而不需要移动或复制大量元素。这使得链表在需要频繁进行插入和删除操作的场景中比数组更高效。   
5. **类型多样性**:链表中的节点可以存储不同类型的数据,这使得链表具有更高的灵活性。   
6. **头节点和尾节点**:链表通常有一个头节点(first node)和一个尾节点(last node)。头节点是链表的起始点,尾节点则指向链表的最后一个节点或包含一个特殊的标识来表示链表的结束。   
7. **循环链表**:在某些情况下,链表的尾节点会指向头节点,形成一个循环链表(Circular Linked List)。这种链表在处理某些问题时(如循环遍历)会更加方便。   
   
链表有多种类型,包括单向链表(每个节点只有一个链接指向下一个节点)、双向链表(每个节点有两个链接,一个指向前一个节点,一个指向下一个节点)和循环链表等。链表在编程中有很多应用,例如实现栈、队列、图等数据结构,或者在需要动态添加和删除元素的场景中作为数组的替代品。   
> 栈(Stack)   

栈(Stack)是一种特殊的线性数据结构,它遵循后进先出(LIFO,Last In First Out)的原则。栈中的数据元素(通常称为“项”或“元素”)只能在栈顶进行插入(push)和删除(pop)操作。   
栈的主要特点包括:   
1. **后进先出(LIFO)**:最后添加到栈中的元素将是最先被移除的。这种操作原则使得栈在处理具有后入先出特性的问题时非常高效。   
2. **栈顶**:栈只允许在其一端(称为栈顶,top)进行插入和删除操作。   
3. **栈底**:栈的另一端(称为栈底,bottom)是固定的,不允许进行插入和删除操作。栈底通常用于指向栈中第一个被插入的元素。   
4. **空栈**:不包含任何元素的栈称为空栈。   
5. **栈的操作**:   
    - **push(压栈)**:将一个新元素添加到栈顶。   
    - **pop(弹栈)**:从栈顶移除一个元素,并返回该元素的值。如果栈为空,则此操作可能导致错误。   
    - **peek(查看栈顶)**:返回栈顶元素的值,但不从栈中移除它。   
    - **isEmpty(检查是否为空)**:检查栈是否为空。   
    - **size(获取栈的大小)**:返回栈中元素的数量。   
   
> 栈在多种应用场景   

- 函数调用和返回:在计算机程序的执行过程中,函数调用时会将参数和局部变量等信息压入调用栈中,函数返回时则从栈中弹出这些信息。   
- 表达式求值:在解析和计算算术表达式时,栈被用来存储中间结果和操作符。   
- 后缀表达式计算:后缀表达式(或逆波兰表达式)的计算可以直接使用栈来实现。   
- 浏览器历史记录:浏览器的后退和前进按钮功能可以通过栈来实现,其中浏览历史记录可以看作是栈中的元素。   
- 括号匹配:在解析文本或代码时,栈可以用来检查括号(如圆括号、方括号、花括号等)是否匹配。   
   
栈可以用数组来实现,也可以用链表来实现。数组实现栈通常具有更高的效率,因为数组的内存是连续的,而链表中的元素是分散的。但是,在某些特殊情况下(如动态内存分配),链表实现栈可能更加合适。   
> 有关栈操作的部分代码   

#include <iostream>  

#include <stack>  

using namespace std;

    

int main() {  

    // 创建一个空的int类型的栈  

    stack<int> myStack;  

  

    // 压栈操作  

    myStack.push(1);  

    myStack.push(2);  

    myStack.push(3);  

  

    // 查看栈的大小  

    cout << "Size of stack: " << myStack.size() << endl;  

  

    // 查看栈顶元素  

    cout << "Top element: " << myStack.top() << endl;  

  

    // 弹栈操作  

    myStack.pop();  

    cout << "Popped element, new top element: " << myStack.top() << endl;  

  

    // 再次查看栈顶元素  

    cout << "Top element after pop: " << myStack.top() << endl;  

  

    // 检查栈是否为空  

    if (myStack.empty()) {  

        cout << "Stack is empty." << endl;  

    } 

    else {  

        cout << "Stack is not empty." << endl;  

    }  

  

    // 继续弹栈操作,直到栈为空  

    while (!myStack.empty()) {  

        cout << "Popping: " << myStack.top() << endl;  

        myStack.pop();  

    }  

  

    // 再次检查栈是否为空  

    if (myStack.empty()) {  

        cout << "Stack is empty now." << endl;  

    }  

  

    return 0;  

}


> 队列(Queue)   

队列(Queue)是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。队列中没有元素时,称为空队列。队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以又称为先进先出(FIFO—first in first out)线性表。   
队列的主要操作包括:   
1. **Enqueue(入队)**:在队列的尾部添加一个元素。如果队列已满,则无法进行此操作。   
2. **Dequeue(出队)**:从队列的头部移除一个元素,并返回该元素。如果队列为空,则无法进行此操作。   
3. **Front(队首)**:返回队列的第一个元素,但不删除它。如果队列为空,则无法返回任何元素。   
4. **Rear(队尾)**:返回队列的最后一个元素,但不删除它。如果队列为空,则无法返回任何元素。注意,不是所有的队列实现都提供此操作。   
5. **IsEmpty(是否为空)**:检查队列是否为空。   
6. **Size(大小)**:返回队列中的元素数量。   
   
队列在计算机科学中有广泛的应用,例如:   
- 操作系统中的任务调度,使用队列来保存等待CPU执行的进程或线程。   
- 打印机打印任务管理,多个打印任务按照提交的顺序依次打印。   
- 数据流处理,如网络数据包处理,数据包按照到达的顺序被处理。   
   
队列的实现方式有多种,包括基于数组的循环队列、基于链表的队列等。循环队列是一种高效的队列实现方式,它可以充分利用数组的空间,避免在入队和出队时频繁地移动元素。基于链表的队列则更加灵活,可以动态地分配和释放内存   
> 有关队列操作的部分代码   

#include <iostream>  

#include <queue>  

using namespace std;

int main() {  

    // 创建一个int类型的队列  

    std::queue<int> q;  

  

    // 入队操作  

    q.push(1);  

    q.push(2);  

    q.push(3);  

  

    // 输出队列大小  

    cout << "Size of queue: " << q.size() << endl;  

  

    // 判断队列是否为空  

    if (q.empty()) {  

        cout << "Queue is empty." << endl;  

    } else {  

        cout << "Queue is not empty." << endl;  

  

        // 输出队首元素  

        cout << "Front element: " << q.front() << endl;  

  

        // 输出队尾元素(注意:对于std::queue,通常不提供直接访问队尾元素的接口)  

        // 但在某些实现中,可以通过其他方式(比如循环遍历)间接访问  

  

        // 出队操作  

        int frontElement = q.front();  

        q.pop();  

        cout << "Popped element: " << frontElement << endl;  

  

        // 再次输出队列大小  

        cout << "Size of queue after pop: " << q.size() << endl;  

    }  

  

    // 遍历队列并输出所有元素  

    cout << "Elements in queue: ";  

    while (!q.empty()) {  

        cout << q.front() << " ";  

        q.pop();  

    }  

    cout << endl;  

  

    return 0;  

}

   
> 树形数据结构   

> 树   

在数据结构中,树(Tree)是一种非线性的数据结构,它由一个根节点(root node)和若干个不相交的子树(subtree)组成,每个子树同样是一棵树。树的定义是递归的,即除了根节点外,每个节点都可以被看作是子树的根节点。   
> 基本概念   

1. **节点(Node)**:树的基本单元,包含数据和指向其子节点的链接。   
2. **根节点(Root Node)**:树的起始节点,是树中唯一没有父节点的节点。   
3. **子节点(Child Node)**:每个节点可以有零个或多个子节点,这些子节点由指向它们的链接相连。   
4. **父节点(Parent Node)**:除根节点外,每个节点都有且仅有一个父节点。   
5. **兄弟节点(Sibling Nodes)**:具有相同父节点的节点称为兄弟节点。   
6. **叶子节点(Leaf Node)**:没有子节点的节点称为叶子节点或终端节点。   
7. **内部节点(Internal Node)**:非叶子节点称为内部节点或分支节点。   
8. **树的度(Degree of a Tree)**:树中所有节点的度的最大值。节点的度是指该节点的子节点数量。   
9. **树的深度(Depth of a Tree)**:从根节点到最远叶子节点的最长路径上的节点数。   
10. **树的层次(Level of a Tree)**:根节点为第一层,根节点的子节点为第二层,依此类推。   
   
> 树的分类   

1. **二叉树(Binary Tree)**:每个节点最多有两个子节点的树。   
    - **满二叉树(Full Binary Tree)**:所有非叶子节点都有两个子节点的二叉树。   
    - **二叉搜索树(Binary Search Tree, BST)**:对于任意节点,其左子树上所有节点的值都小于该节点的值,其右子树上所有节点的值都大于该节点的值。   
    - **平衡二叉树(Balanced Binary Tree)**:任意节点的左右子树的高度差不超过1的二叉树。   
    - **完全二叉树(Complete Binary Tree)**:除最后一层外,其他各层的节点数都达到最大个数,并且最后一层所有的节点都尽量靠左排列的二叉树。   
2. **n叉树(N-ary Tree)**:每个节点最多有n个子节点的树,其中n是一个正整数。   
3. **森林(Forest)**:m(m≥0)棵互不相交的树的集合。对树中任意节点而言,其子树的集合就是森林。   
   
> 树的遍历   

树的遍历是指按照某种特定的规则访问树中的所有节点,并且每个节点只被访问一次。常见的遍历方式有:   
1. **前序遍历(Pre-order Traversal)**:   
   
                先访问根节点,然后遍历左子树,最后遍历右子树。   
** 2.    中序遍历(In-order Traversal)**:   
                在二叉搜索树中,先遍历左子树,然后访问根节点,   
                最后遍历右子树。对于一般树,这个定义并不唯一。   
** 3.     后序遍历(Post-order Traversal)**:   
                 先遍历左子树,然后遍历右子树,最后访问根节点。   
** 4.      层次遍历(Level-order Traversal)**:   
                 从上到下、从左到右逐层访问树的节点(非强性规定)   
                 通常使用队列来实现。   
树结构在计算机科学中有广泛的应用,如文件系统的目录结构、编译器中的语法树、路由算法中的路由表等。   
   
   
   
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值