基本概念
线性表是一种逻辑结构,相同数据类型的n个数据元素的有限序列,除第一个元素外,每个元素有且仅有一个直接前驱,除最后一个元素外,每个元素有且仅有一个直接后继。
线性表具有以下特点:
- 元素个数有限
- 逻辑上元素有先后次序
- 数据类型相同
- 仅讨论元素间的逻辑关系
数组和链表
– | 数组 | 链表 |
---|---|---|
优点 | 随机访问性强;查找速度快 | 插入删除速度快;内存利用率高,不会浪费内存;大小没有固定,扩展和灵活 |
缺点 | 插入和删除效率低;可能浪费内存;内存空间要求高,必须有足够的连续内存空间;数组大小固定,不能动态扩展 | 不能随机查找,必须从第一个开始遍历,查找效率低 |
– | 数组 | 链表 |
---|---|---|
读取 | O(1) | O(n) |
插入 | O(n) | O(1) |
删除 | O(n) | O(1) |
单链表,双向链表,循环链表
单向链表
- 数据域
- 后继指针
private class Node {
// 链表节点的嵌套
T item; // 节点内容
Node next; // 后续节点
}
双向链表
- 数据域
- 前驱指针
- 后继指针
private class Node {
// 链表节点的嵌套
T item; // 节点内容
Node prior, next; // 前驱节点和后续节点
}
循环链表
循环单链表
与单链表的区别在于,表中最后一个节点的指针不为null,而改为指向头结点(第一个节点),从而整个链表形成一个环。判断循环单链表是否为空,判断是否等于头指针。只有一个尾指针的循环单链表,可以很方便的操作表头和表尾,因为尾指针的后继就是头指针0(1)。
循环双链表
与双链表的区别在于,头结点的prior指针指向尾节点,尾节点的next指针指向头结点。
栈与队列
栈(Stack)和队列(Queue)是两种操作受限的线性表。这种受限表现在∶栈的插入和删除操作只允许在表的尾端进行(在栈中成为“栈顶”),满足"First In Last Out";队列只允许在表尾插入数据元素,在表头删除数据元素,满足"First ln First Out"。都可以通过顺序结构和链式结构实现。插入与删除的时间复杂度都是o (1),在空间复杂度上两者也一样。
栈(Stack)应用场景:
- 括号问题的求解
- 表达式的转换和求值
- 函数调用和递归实现
- 深度优先搜索遍历
队列(Queue)应用场景:
- 计算机系统中各种资源的管理
- 消息缓冲器的管理
- 广度优先搜索遍历
栈
其实非常好理解,我们将栈可以看成一个箱子
- 往箱子里面放东西叫做入栈
- 往箱子里面取东西叫做出栈箱子的底部叫做栈底
- 箱子的顶部叫做栈顶
说到栈的特性,肯定会有一句经典的言语来概括:先进后出
- 往箱子里边放苹果,箱子底部的苹果想要拿出来,得先把箱子顶部的苹果取走才行
队列
其实队列非常好理解,我们将队列可以看成排队
- 有人到指定的地点了–>出队
- 有新的人加入了–>入队
相对于栈而言,队列的特性是︰先进先出
- 先排队的人肯定能先打到饭!
实战,两个栈实现一个队列
必须实现两点︰
- 如果stackPush要往stackPop中压数据,必须一次
性把stackPush中的数据全部压入。 - 如果stackPop不为空, stackPush绝对不能向
stackPop中压入数据。
一对多的线性结构–树
[一对多]指一个元素只能有一个前驱,但是可以有多个后继。
- 结点拥有的子树数被称为结点的度(Degree)。
- 度为0的结点称为叶节点(Leaf)或终端结点,度不为0的结点称为分支结点。
- 除根结点外,分支结点也被称为内部结点。
- 结点的子树的根称为该结点的孩子(Child),该结点称为孩子的双亲或父结点。
- 同一个双亲的孩子之间互称为兄弟。
- 树的度是树中各个结点度的最大值。
- **结点的层次(Level)**从根开始定义起,根为第一层,根的孩子为第二层。
- 双亲在同一层的结点互为堂兄弟。
- 树中结点的最大层次称为树的深度(Depth)或高度。
- 如果将树中结点的各个子树看成从左到右是有次序的,不能互换的,则称该树为有序树,否则称为无序树。
- 森林是m(m> =0)棵互不相交的树的集合。
二叉树
二叉树(Binary Tree)是每个节点最多有两个子树的树结构。通常子树被称作"左子树" (left subtree)和"右子树"(right subtree) 。
二叉树的特点:
- 二叉树不存在度大于2的结点。
- 二叉树的子树有左右之分,次序不能颠倒。
斜树
所有的结点都只有左子树的二叉树叫左斜树。所有的结点都只有右子树的二叉树叫右斜树。这两者统称为斜树。
斜树每一层只有一个结点,结点的个数与二叉树的深度相同。其实斜树就是线性表结构。
满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
满二叉树具有如下特点∶
- 叶子只能出现在最下一层
- 非叶子结点的度一定是2
- 同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。
完全二叉树
若设二叉树的高度为h,除第h层外,其它各层(1~h-1)的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
完全二叉树的特点∶
- 叶子结点只能出现在最下两层最下层叶子在左部并且连续
- 同样结点数的二叉树,完全二叉树的深度最小
平衡二叉树
平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:
- 它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
- 非叶子节值大于左边子节点、小于右边子节点
- 没有值相等重复的节点
红黑树
因为平衡二叉树查询性能和树的层级(h高度)成反比, h值越小查询越快、为了保证树的结构左石内端数据大致平衡降低二叉树的查询难度一般会采用一种算法机制实现节点数据结构的平衡,实现了这种算法就有红黑树。红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。
红黑树的特性:
- 每个节点或者是黑色,或者是红色。
- 根节点是黑色。
- 每个叶子节点(NIL)是黑色。[注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
- 如果一个节点是红色的,则它的子节点必须是黑色的。
- 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
B+ 树
B+树充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。
例如MySQL的数据库索引查找。
- B+树的非叶子节点不保存关键字记录的指针,这样使得B+树每个节点所能保存的关键字大大增加;
- B+树叶子节点保存了父节点的所有关键字和关键字记录的指针,每个叶子节点的关键字从小到大链接;
- B+树的根节点关键字数量和其子节点个数相等;
- B+的非叶子节点只进行数据索引,不会存实际的关键字记录的指针,所有数据地址必须要到叶子节点才能获取到,所以每次数据查询的次数都一样;
二叉树遍历
前序遍历︰先访问根结点,然后遍历左子树,最后遍历右子树。
中序遍历∶先遍历左子树,然后遍历根结点,最后遍历右子树。
后序遍历∶先遍历左子树,然后遍历右子树,最后遍历根结点。
层次遍历∶从上到下逐层遍历,在同一层中,按从左到右的顺序遍历。
图
定义︰图(graph)是由一些点(vertex)和这些点之间的连线(edge)所组成的﹔其中,点通常被成为"顶点(vertex)",而点与点之间的连线则被成为"边或弧"(edege)。通常记为,G=(V,E)。
根据边是否有方向,将图可以划分为∶无向图和有向图
邻接点和度
邻接点
一条边上的两个顶点叫做邻接点。
例如,上面无向图G0中的顶点A和顶点C就是邻接点。
在有向图中,除了邻接点之外;还有"入边"和"出边"的概念。
顶点的入边,是指以该顶点为终点的边。而顶点的出边,则是指以该顶点为起点的边。
例如,上面有向图G2中的B和E是邻接点;<B,E>是B的出边,还是E的入边。
度
在无向图中,某个顶点的度是邻接到该顶点的边(或弧)的数目。
例如,上面无向图G0中顶点A的度是2。
在有向图中,度还有"入度"和"出度"之分。
某个顶点的入度,是指以该顶点为终点的边的数目。而顶点的出度,则是指以该顶点为起点的边的数日。顶点的度=入度+出度。
例如,上面有向图G2中,顶点B的入度是2,出度是3,顶点B的度=2+3=5。
邻接矩阵
邻接矩阵是指用矩阵来表示图。它是采用矩阵来描述图中顶点之间的关系(及弧或边的权)。
假设图中顶点数为n,则邻接矩阵定义为∶
通常采用两个数组来实现邻接矩阵︰一个一维数组用来保存顶点信息,一个二维数组来用保存边的信息。
邻接矩阵的缺点就是比较耗费空间。
邻接表
邻接表是图的一种链式存储表示方法。它是改进后的“邻接矩阵”,他的缺点是不方便判断两个顶点之间是否有边,但是相对邻接表来说更省空间。
图的遍历
深度优先遍历
图的深度优先搜索(Depth First Search),和树的前序遍历比较类似。简称BFS。
它的思想︰假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点重复上述过程,直至图中所有顶点都被访问到为止。
显然,深度优先搜索是一个递归的过程。
一路走到头,不撞墙不回头
广度优先遍历
广度优先搜索算法(Breadth First Search),又称为"宽度优先搜索"或"横向优先搜索",简称BFS。
它的思想是︰从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。
换句话说,广度优先搜索遍历图的过程是以v为起点,由近至远依次访问和v有路径相通且路径长度为1,2…的顶点。
一层一层