目录
数据结构与算法密切相关;
参考:
- [数据结构]——链表(list)、队列(queue)和栈(stack)
//讲的很详细 需要仔细看 - 《大话数据结构》
1. 基础
//数据结构基础
1.1. 基本概念
1.1.1. 基本概念
- 逻辑结构
数据对象中数据元素之间的相互关系。 //P7- 集合结构:数据元素无相互间的关系;
- 线性结构:一对一;
- 树形结构:一对多;
- 图形结构:多对多;
- 物理结构
即存储结构,数据的逻辑结构在计算机中的存储形式;
包括顺序存储结构和链式存储结构;- 顺序存储:地址连续;
- 链式存储:存储单元未必连续;
1.1.2. 数据结构 类型概述
- 队列(queue):
- **栈(stack):**先进后出。按照顺序依次出入
- **串(string):**字符串;
- 注解
- 操作对数据的进入和取出顺序有严格要求选择栈,而且必须是先进后出的。对顺序没有要求的时候可以选用链表。
1.1.3. 线性表
-
定义:
-
分类:
- 顺序存储结构 --普通顺序存储
- 无序线性表:插入删除效率尚可;因无序,查找效率太低;
- 有序线性表:插入删除耗时;查找速度快(可使用折半、插值、斐波那契等);
//P314
- 顺序存储结构 --普通顺序存储
-
链式存储结构
- 单链表
- 静态链表
- 循环链表
- 双向链表
-
优缺:
1.2. 辨析 //重要
1.2.1. 结构
- 线性表
- 第一个数据元素:无前驱;
- 最后一个:无后继,一个;
- 中间元素:前驱、后继各一个;
- 树
- 根节点:无双亲;
- 叶节点:污孩子,可以多个;
- 中间节点:一个双亲多个孩子;
1.2.2. 操作类型
- 线性表更加关注 单个元素 的操作;例:查找、插入或删除 一个元素。
栈和队列是特殊的线性表; - 串:很大的区别于线性表;串中更多的是
查找子串位置、读取指定位置的子串、替换子串等操作;
2. 链表 List
2.1. 实践使用
- 数组与链表
- 当需要存储多个相同类型的数据时,优先使用数组。数组可以通过下标直接访问(即随机访问)。
//数组的优势 - 正是由于这个优点,数组无法动态添加或删除其中的元素,而链表弥补了这种缺陷。
//数组的不足 链表的特点
2.2. 链表详解
2.2.1. 单向链表
单向链表,即只有一个指针,该指针指向下一个元素的地址。通常只要知道链表首地址,则可以遍历整个链表。由于链表节点是在堆区动态申请的,其地址并不是连续的,因此无法进行随机访问,只有通过前一节点的next指针才能定位下一节点的地址。
- 代码示例
2.2.2. 双向链表
-
优缺
- 单向链表只能向后遍历,无法逆序遍历,而使用更广泛的双向链表,即节点内部增加一个字段prev,用以存储该节点的前*一个节点地址。
- 双向链表可以双向遍历,但仍然只能顺序访问,无法像数组那样随机访问。
-
双向链表的List实现 //STL实现的双向链表
- List是stl实现的双向链表,与向量(vectors)相比,
- 允许快速的插入和删除,但是随机访问却比较慢(缺)。
- #include //使用时需要添加头文件;
-
语法格式
------ List定义和初始化: list<int>lst1; //创建空list list<int> lst2(5); //创建含有5个元素的list list<int>lst3(3,2); //创建含有3个元素的list list<int>lst4(lst2); //使用lst2初始化lst4 list<int>lst5(lst2.begin(),lst2.end()); //同lst4 ------- List常用操作函数: Lst1.assign() 给list赋值 Lst1.back() 返回**最后一个**元素 Lst1.begin() 返回指向第一个元素的迭代器 Lst1.clear() 删除所有元素 Lst1.empty() 如果list是空的则**返回true** //返回值为true Lst1.end() 返回末尾的迭代器 Lst1.erase() 删除一个元素 Lst1.front() 返回第一个元素 Lst1.get_allocator() 返回list的配置器 Lst1.insert() 插入一个元素到list中 Lst1.max_size() 返回list能容纳的最大元素数量 Lst1.merge() 合并两个list Lst1.pop_back() 删除最后一个元素 Lst1.**pop**_front() 删除第一个元素 Lst1.push_back() 在list的**末尾添加**一个元素 Lst1.push_front() 在list的**头部添加**一个元素 Lst1.rbegin() 返回指向第一个元素的逆向迭代器 Lst1.remove() 从list删除元素 Lst1.remove_if() 按指定条件删除元素 Lst1.rend() 指向list末尾的逆向迭代器 Lst1.resize() 改变list的大小 Lst1.reverse() 把list的元素倒转 Lst1.size() 返回list中的元素个数 Lst1.sort() 给list排序 Lst1.splice() 合并两个list Lst1.swap() 交换两个list Lst1.unique() 删除list中重复的元素
参考:
- C++之list的使用总结及常用list操作
//有具体语法讲解和代码示例 - MFC中CList类使用方法
//双向链表类,实际使用较多
3. 栈 Stack 和 队列 Queue
栈和队列属于特殊的线性表,所以和线性表一样,共有两种存储结构:顺序存储和链式存储。
//栈(stack)
栈的使用,具体概念、栈的实现;
3.1. 实践使用
概念区分
-
堆和栈的区别 之 数据结构和内存 //很重要 必看
by叫我大侠 -
栈数据操作方式 概述 //后进先出 与队列不同之处
- 栈的特点与队列正好相反,按照数据入栈顺序逆序出栈,即**“后进先出”**。
- 通常会对栈进行频繁入栈和出栈,与队列类似,一般使用定长数组存储栈元素,而不是动态申请节点空间。
- 具体进出栈过程
与队列类似,使用一个结构体存储当前栈的大小和容量。由于入栈和出栈都在栈顶,所以只需要一个size字段存储当前栈的大小。每次入栈时,将size向后移动;出栈时将size向前移动,注意不要超过容量,初始化size为0。
-
分为 顺序存储 和 链式存储 两种方式
-
栈操作
- c++ stl栈stack的头文件为:
#include
- c++ stl栈stack的头文件为:
-
c++ stl栈stack的成员函数介绍
操作 比较和分配堆栈 **bool** empty(); //判断是否为空 堆栈为空则返回**真** **void** Pop(); 移除栈顶元素 **void** Push(**const** T & s); 在栈顶增加元素 **size_t** size(); 返回栈中**元素数目** T & Top(); 返回栈顶元素
-
栈操作参考示例
- C++中栈结构建立与操作详细解析
//含有术语说明和代码 - C++实现栈的基本操作
// - 代码实现栈的各种操作
//看懂
- C++中栈结构建立与操作详细解析
注意:
- 链表、队列和栈的概念介绍完毕,虽然很简单,但是就像数组那样简单而又广泛使用。以上代码均为C风格代码。
- 在C++中,因为STL中已经包含了这三种数据结构,并使用模板类进行书写。其中队列和栈为动态增长的,不必要初始其容量。当需要使用这三种数据结构时,优先使用STL提供的代码,而不是自己动手实现。
3.2. 栈的详解
-
分类
- 顺序栈:栈的顺序存储结构
- 顺序栈的两栈共享空间;
- 链栈:栈的链式存储结构;
- 顺序栈:栈的顺序存储结构
-
后缀表达式与栈的结合
-
注意:
- 链栈没有头节点;
- 栈是在内存中使用;
- 顺序栈、链栈:时间复杂度均为O[1];
3.3. 实践使用
- 队列数据操作方式 //先进先出
- 队列即按照数据到达的顺序进行排队,每次新插入一个节点,将其插到队尾;每次只有对头才能出队列。简言之,对于数据元素的到达顺序,做到“先进先出”。
- 由于队列通常频繁的插入与删除,为了高效,一般使用固定长度的数组进行实现,并且可循环使用数组空间,所以要经常处理当前队列是否为满或为空。
- 如需要动态长度,可以用链表实现,只需要同时记住链表首地址(队列的头)和尾地址(队列的尾)。
3.4. 队列详解
- 定义:
只允许在 队尾插入,队头删除 的 线性表; //FIFO模式 - 分类
- 顺序队列:
- 循环队列:
- 链队列:线性表的单链表+尾进头出;
- 顺序队列:
4. 树 Tree
//大话数据结构 P151
4.1. Tree 概述
- 概念
4.2. 二叉树 Binary Tree
5种基本类型;3种特殊二叉树;
4.2.1. Binary Tree 概述
- 二叉树特点
- 每个节点最多两棵子树;
- 左右子树有顺序,不可颠倒;
- 区分左右子树,哪怕只有一棵子树;
- 特殊二叉树 //P166
- 斜树
- 满二叉树
- 完全二叉树
区分:满二叉树一定是完全二叉树,但完全二叉树不一定是满的;
4.2.2. 遍历 二叉树
//遍历名称针对 根节点 4种主要遍历方法 P174
- 前序遍历
中左右;左到底; - 中序遍历
左中右; - 后序遍历
左右中 - 层序遍历
按层遍历;
4.3. 搜索树
参考
5. 串 String
5.1. 概述
串是由零个或多个字符组成的有限序列,又称字符串。
- 字符串查找 算法
- KMP算法及改进 //大话数据结构
- Sunny算法
- Boyer–Moore算法
5.2. 算法
5.2.1. 朴素模式匹配算法
普通遍历方法;蛮力算法;
5.2.2. KMP 算法
//字符串查找算法
- 优缺点
- 最坏情况下也是o(m+n)的,而遍历(普速模式匹配)是o(m*n);
参考
- KMP 算法
//极客学院 包括:BM算法、Sunday算法;
5.2.3. Boyer–Moore算法
5.2.4. Sunday 算法
6. 图
7. 应用
7.1. 排序
- 数组排序
- 链表排序
- 表外排序
8. 区分 数据结构
8.1. 堆
概念区分
-
栈与堆
-
堆与二叉树
-
概念
- 堆是一种经过排序的树形数据结构,每个节点都有一个值。
- 通常我们所说的堆的数据结构,是指二叉堆。
- 堆的特点是根节点的值最小(或最大),且根节点的两个子树也是一个堆。
-
区分
- 最大堆:父节点的键值总是大于或等于任何一个子节点的键值;
- 最小堆:父节点的键值总是小于或等于任何一个子节点的键值。 //均来自二叉堆
-
其他
由于堆的这个特性,常用来实现优先队列,堆的存取是随意的,
这就如同我们在图书馆的书架上取书,虽然书的摆放是有顺序的,
但是我们想取任意一本时不必像栈一样,先取出前面所有的书,
书架这种机制不同于箱子,我们可以直接取出我们想要的书。
//堆排序;
参考:
- 二叉堆
//百度百科
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。
二叉堆有两种:最大堆和最小堆。 - 堆树(最大堆、最小堆)详解
8.2. 堆与二叉树的区别
-
区别
最长见的数结构是搜索树,最常见的堆是大(小)根堆。差别就在于,堆的左右节点是没有大小关系的,而树一般是左中右(由大到小)。 -
树的分类
参考:
- 二叉树与堆
//可以看看