开头:数据结构和算法

目录: 

  1. 基础

  2. 算法基础
    1. 数据结构
      数据结构是由某一数据对象及该对象中所有数据元素之间的关系组成。
      数据在计算中的存储方式,也称为数据的物理结构。
    2. 基本概念
      1. 数据
      2. 数据对象
      3. 数据元素
    3. 4种基本的逻辑结构
      1. 线性结构
      2. 集合结构
      3. 树形结构
      4. 图状结构
        数据逻辑结构可分为线性结构和非线性结构两类。集合结构、树形结构、图状结构,统称为非线性结构。
    4. 数据存储主要有4种基本方法
      1. 顺序存储方法
        最基本的存储方式,一般借助数据来实现。比如:ArrayList
      2. 链式存储方法
        比如:LinkedList
      3. 索引存储方法
        比如:B树、B+树
      4. 散列存储方法
        比如:散列
    5. 算法和算法分析
      1. 算法
        1. 算法是为某一个特定问题而制定的求解步骤的一种描述,它是有限的指令序列,其中每一条指令表示一个或多个操作。一个算法应当具有下列重要特性:
          1. 输入
          2. 输出
          3. 确定性
          4. 有穷性
          5. 有效性
        2. 比如:查找、删除、插入、修改、求长度、定位、排序等操作
      2. 算法分析和算法复杂度
        1. 时间复杂度
        2. 空间复杂度
  3. 线性表
    1. 线性表的定义和基本运算
      1. 线性表的定义
        线性表是一种线性结构。线性结构的特点是数据元素之间是一种线性关系,数据元素“一个接一个地排列”。
      2. 特点:在数据元素的非空有限集中
        1. 存在唯一的一个被称为“第一个”的数据元素
        2. 存在唯一的一个被称为“最后一个”的数据元素
        3. 除第一个之外,集合中的每个元素均只有一个前驱
        4. 除最后一个之外,集合中的每个元素均只有一个后继
      3. 线性表的运算
        求长度、插入元素、删除元素、查找元素、修改元素
    2. 线性表的存储结构
      1. 顺序存储结构
        1. 实现:在Java中可以使用数组实现
        2. 算法:初始化、求表长、插入元素、删除元素、查找元素、修改元素
      2. 链式存储结构
        1. 单链表(每个节点包含两个部分:存放数据信息的称为数据域,存放其后继地址的称为指针域,最后一个节点的指针为空指针
          1. 实现:在单链表的头部插入节点、在单链表的尾部插入节点
          2. 算法:初始化、求表长、查找元素、插入元素、删除元素、修改元素
        2. 循环链表(如果单链表的最后一个节点的指针指向链表的头指针
        3. 双链表(每个节点包含三个部分:存放其前驱地址的指针域,存放数据信息的称为数据域,存放其后继地址的称为指针域
        4. 静态链表
      3. 总结
        顺序表顺序插入快、查询、修改效率高,链表表中插入快、删除效率高
    3. 实例
      1. ArryList(顺序储存)
      2. LinkedList(链式存储中的双链表)
  4. 栈与队列
    1. 栈(Stack)
      1. 栈模型
        1. 栈是限定仅在表的一端(一般指表尾部)进行插入和删除操操作的线性表。
        2. 允许插入、删除的这一端称为栈顶(Top),另一端称为栈底(Bottom)。栈的插入操作通常称为入栈或进栈(push),而栈的删除操作则称为出栈或退栈(pop)。
        3. 当表中没有元素时称为空栈。
      2. 栈实现
        栈是一种特殊的线性表,因此栈也可以采用两种存储结构:顺序存储结构和链式存储结构。
        1. 顺序栈(在Java中可以使用ArrayList实现)
          1. 初始化
          2. 入栈:在表的尾部插入
          3. 出栈:删除表的最后一个元素
        2. 链表栈(在Java中可以使用LinkedList实现)
          1. 入栈:使用LinkedList的add(E e)方法
          2. 出栈:使用LinkedList的removeLast()
        3. 选用顺序栈作为栈,因为两者插入删除效率相差不大,但是链表栈所占用的内存大
      3. 栈的应用
        1. Java虚拟机栈中的栈帧
        2. 二叉树的先序、中序、后序的非递归遍历。
    2. 队列(Queue)
      1. 队列模型
        1. 队列是限定在表的一端进行插入,在表的另一端进行删除操作的线性表。
        2. 允许插入的一端称为队尾(rear),允许删除的一端称为队头(front)。队列的插入操作通常称为入队(offer),而队列的删除操作则称为出队(poll)。
        3. 当队列中没有元素的时候称为空队列。
      2. 队列实现
        与线性表、栈类似,队列也有顺序存储和链式存储两种存储方式。
        1. 顺序队列(在Java中可以使用ArrayList实现)
          1. 初始化
          2. 入队:在表的尾部插入
          3. 出队:删除表的第一个元素
        2. 链式队列(在Java中可以使用LinkedList实现,表尾插入、表头删除)
          1. 初始化
          2. 入队:使用LinkedList的offerLast(E e)方法
          3. 出队:使用LinkedList的pollFirst() 方法
        3. 使用链式队列作为队列,因为链表队列比顺序队列插入删除效率高。
      3. 队列的应用
        1. 消息队列
        2. 程序设计中的二叉树的层次遍历、图的广度优先遍历基数排序、缓冲区的循环使用
        3. 操作系统中的作业管理、进程调度、I/0请求处理
  5. 数组和串
    1. 数组的顺序存储
    2. 特殊矩阵的压缩存储
    3. 稀疏矩阵
    4. 广义表
    1. 树的基本概念
      1. 树的定义
        树是由n(n>=0)个节点组成的有限集合。
        空树、根节点、子树
        树是一种非线性数据结构。
      2. 特点
        1. 它的每一个节点可以有零个或多个后继,除根节点外的所有节点有且仅有一个前驱
        2. 这些节点按分支关系组织起来,清晰地反应了数据元素之间的层次关系,数据元素之间存在一对多的关系。
      3. 基本术语
        结点、树叶(叶子)、非终端结点、孩子结点、父结点、祖先结点、子孙结点、兄弟结点、
        度:一个结点拥有子树的个数,称为该结点的度
        树的度:树内各结点的度的最大值。
        深度根结点到该结点的最大层数称为深度。如空树的深度为0,只有一个根结点的深度为1;
        高度叶子节点到该结点的最大层数称为高度。如空树的高度为1,只有一个根结点的高度为1;
        树的深度(高度):树中结点所处的最大层数称为树的高度。如空树的高度为0,只有一个根结点的树高度为1。
        有序树:若有一颗树中所有子树从左到右的排序是由顺序的,不能颠倒次序,称该树为有序树。
        在有序树中,最左边的子树的根称为第一个孩子,最右下的称为最后一个孩子。比如:二叉树
        无序树
        森林
      4. 树的基本算法
        构造一个树、清空树、获取给定结点的第i个孩子、获取给定结点的双亲、遍历树
         
    2. 二叉树
      1. 二叉树
        1. 概念
          1. 二叉树是n(n>=0)个结点的有限集,它或为空,或有一个根节点与两个不想交的、被分别称为左子树和右子树的二叉树组成。
          2. 二叉树是有序的,即若将其左、右子树颠倒,就成为了另一棵不同的二叉树。
          3. 二叉树中每个结点最多只能有两颗子树,且有左右之分。
        2. 性质
          1. 在非空二叉树中,第i层的结点总数不超过 , i>=1;
          2. 深度为h的二叉树最多有个结点(h>=1),最少有h个结点; 
          3. 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
        3. 二叉树的存储
          1. 顺序存储:在Java中可以使用数组或者ArrayList存储。(层次遍历)
          2. 链式存储:链表中的每个结点由三个域组成,除了数据域外,还有两个指针域,分别用来给出左孩子和右孩子所在的链结点的存储地址。当左孩子或右孩子不存在时,相应指针域为空(用null表示)。
        4. 二叉树的遍历
          1. 递归实现
            1. 先序遍历
            2. 中序遍历
            3. 后续遍历
          2. 非递归实现
            1. 先序遍历(利用栈的特性来实现)
            2. 中序遍历(利用栈的特性来实现)
            3. 后序遍历(利用栈的特性来实现)
            4. 层次遍历(利用队列实现)
      2. 满二叉树
        1. 概念:一颗深度为h且有个结点的二叉树称为满二叉树。或者说,在一颗二叉树中,如果所有的分支结点都存在左子树和右子树,并且所有的叶子节点都在同一层,这样的二叉树称作满二叉树
      3. 完全二叉树
        1. 概念:一颗深度为h的有n个结点的二叉树,对树中的结点按从上至下,从左至右的顺序进行编号,如果编号为i(0<=i<=n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这颗二叉树为完全二叉树
        2. 特点:叶子节点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。
        3. 性质
          1. 具有n个结点的完全二叉树的深度为 (注:[ ]表示向下取整)
          2. 有N个结点的完全二叉树各结点如果用顺序方式存储(层次遍历),则结点之间有如下关系:
            1. 若对二叉树的根节点从1开始编号,则 相应的i结点,如果i>1,则其父结点的编号为i/2;
              如果2*i<=N,则其左孩子(即左子树的根结点)的编号为2*i;若2*i>N,则无左孩子;
              如果2*i+1<=N,则其右孩子的结点编号为2*i+1;若2*i+i>N,则无右孩子。
            2. 若对二叉树的根节点从0开始编号,则相应的i号结点的父结点的编号为(i-1)/2,左孩子的编号为2i+1(2i+1
      4. 哈夫曼树
        1. 概念
          路径、路径长度、树的路径长度、结点的权、结点的带权路径长度、树的带权路径长度WPL
          带权路径长度最小的二叉树称为哈夫曼树或最优树。
        2. 性质
          1. 哈夫曼树没有度为1的结点
          2. 对于具有n个叶子结点的哈夫曼树共有2n-1个结点。
        3. 构造
          1. 在n个权值结点中,选取权值最小和次小的结点分别为左、右子树构造一棵二叉树,且置新的二叉树根节点的权值为其左、右子树根节点权值之和
          2. 重复步骤1
        4. 应用
          1. 哈夫曼树在编码问题中的应用(哈夫曼编码)
    3. 树和森林
      1. 存储结构
        1. 双亲表示法
        2. 孩子表示法
        3. 孩子兄弟表示法
      2. 树、森林与二叉树的转换
        1. 树转换为二叉树
        2. 森林转换为二叉树
        3. 二叉树还原成树或森林
      3. 树和森林的遍历
      4. 回溯法与树的遍历
        1. N皇后问题
        2. 4皇后问题
  6. 散列
    1. 散列函数
      1. 线性变换法(又可以叫直接法,不常用),这种方法所获得的地址集合和关键字值的集合的大小相同。
      2. 除留取余法(求模法,最简单,最常用)
      3. 数字分析法
      4. 。。。
    2. 处理冲突
      1. 开散列方法(拉链法,又叫分离链接法):就是把发生冲突的结点存储在散列表本身之外。
        比如Java中HashMap就采用这种方法
      2. 开地址法:就是把发生冲突的结点存储在散列表中的另外一个槽中。需用使用一个公式探测散列地址序列
  7. 优先队列(堆)
    1. 模型
      优先队列是允许至少下列两种操作的数据结构:
      insert(插入),等价于入队(enqueue)
      deleteMin(删除最小者),等价于出队(dequeue)
    2. 二叉堆(小顶推、大顶推)
      1. 性质
        1. 结构性质:二叉堆还是一个完全二叉树。所有有完全二叉树的所有性质。
        2. 堆序性质:任意结点小于它的所有后裔。
      2. 基本的堆操作
        1. 构建堆(小顶堆)
        2. insert()
        3. finMin()
        4. deleteMin()
        5. 堆排序(在排序中有,此处没有实现)
          public class BinaryHeap>{
          
              public static final int DEFAULT_CAPACITY = 10;
          
              private int currentSize;      // Number of elements in heap
              private AnyType [ ] array; // The heap array
             
              public BinaryHeap( ){
                  this( DEFAULT_CAPACITY );
              }
          
              public BinaryHeap( int capacity ){
                  currentSize = 0;
                  array = (AnyType[]) new Comparable[ capacity + 1 ];
              }
              
              public BinaryHeap( AnyType [ ] items ){
                      currentSize = items.length;
                      array = (AnyType[]) new Comparable[ currentSize + 2 ];
          
                      int i = 1;
                      for( AnyType item : items )
                          array[ i++ ] = item;
                      buildHeap( );
              }
          
              public void insert( AnyType x ){
              	//如果堆中元素的数量等于数组的容量-1,也就是数组已经填充满了,那么就扩容
              	//注意数组array[0]不存储元素,从array[1]开始存储元素
                  if( currentSize == array.length - 1 )
                      enlargeArray( array.length * 2 + 1 );
          
                  // Percolate up
                  int hole = ++currentSize;
                  for( array[ 0 ] = x; x.compareTo( array[ hole / 2 ] ) < 0; hole /= 2 ) {
                  	array[ hole ] = array[ hole / 2 ];
                  }
                  array[ hole ] = x;
              }
              
              public AnyType findMin( ){
              	if( isEmpty( ) ){
                  	System.out.println("Heap is Empty!");
                  	return null;
                  }
              	for(AnyType t:array) {
              		System.out.print(t+",");
              	}
                  return array[ 1 ];
              }
          
              public AnyType deleteMin( ){
                  if( isEmpty( ) ){
                  	System.out.println("Heap is Empty!");
                  	return null;
                  }
          
                  AnyType minItem = findMin( );
                  array[ 1 ] = array[ currentSize-- ];
                  percolateDown( 1 );
          
                  return minItem;
              }
          
              public boolean isEmpty( ){
                  return currentSize == 0;
              }
          
              public void makeEmpty( ){
                  currentSize = 0;
              }
          
          	private void buildHeap( ){
                  for( int i = currentSize / 2; i > 0; i-- )
                      percolateDown( i );
              }
              
              private void enlargeArray( int newSize ){
                  AnyType [] old = array;
                  array = (AnyType []) new Comparable[ newSize ];
                  for( int i = 0; i < old.length; i++ )
                      array[ i ] = old[ i ];        
              }
          
              //上滤
              private void percolateDown( int hole ){
                  int child;
                  AnyType tmp = array[ hole ];
                  
                  //下滤
                  for( ; hole * 2 <= currentSize; hole = child )
                  {
                      child = hole * 2;
                      if( child != currentSize && array[ child + 1 ].compareTo( array[ child ] ) < 0 ) {
                      	child++;
                      }
                      if( array[ child ].compareTo( tmp ) < 0 )
                          array[ hole ] = array[ child ];
                      else
                          break;
                  }
                  array[ hole ] = tmp;
              }
          }

           

    3. 优先队列的应用
    4. d-堆
    5. 左式堆
      1. 左式堆得性质
      2. 左式堆操作
    6. 斜堆
    7. 二项队列
    8. Java标准库中优先队列
    1. 图的定义和术语
      1. 图的定义
        图是由顶点和边构成的,图的顶点是图的元素,而图的边则表示了元素之间的相互关系。
        具有有向边的图为有向图。
        具有无向变的图为无向图。
      2. 图的特点
        图中的每个元素,可以拥有0~n个前驱,也可以有0~n个后继,即图中元素之间的关系是任意的。
      3. 图的术语
        1.端点和邻接点
        2.顶点的度
        3.完全图、稠密图、稀疏图
        4.子图
        5.路径、回路环
        6.无向图:连通、连通图、连通分量:无向图的极大连通子图称为连通分量
        7.有向图:强连通、强连通图、强连通分量
        注意:任何连通图的连通分量只有一个,即是其自身,非连通的无向图有多个连通分量。
        8.关节点、重连通图
        9.权:每一条边对应的值
    2. 图的存储表示
      1. 邻接矩阵:使用n行n列的2维数组进行存储。如果不是无权图,就用1表示两顶点连通,0表示两顶点没有连通。如果是有权图,就用权值表示两顶点连通。
        1. 图的邻接矩阵存储有下面特点:
          1. 图的邻接矩阵是唯一的。
          2. 无向图的邻接矩阵是按对角线对称的,即a ij = a ji;有向图的邻接矩阵则不一定是对称。
          3. 对于无向图,邻接矩阵的第i行非零元素的个数正好是第i个结点v i的度数。
          4. 对于有向图,邻接矩阵的第i行非零元素的个数正好是第i个结点v i的出度,第i列非零元素的分数正好是第i个结点v i的入度。
          5. 采用邻接矩阵存储图,非常易于确定图中任意两个顶点的边。但是要确定图中共有多少条边,必须按行、列对邻接矩阵的每个元素进行检测。对于一个具有N个顶点的图的邻接矩阵,需要花费O(n的平方)的时间。所以其检索效率较低。
      2. 邻接表:邻接表是一种结合了顺序存储和链式存储技术的存储结构。
        其基本思想是,顺序存储每个顶点,且为每一个顶点建立一个单链表来存储其邻接点,以表示边的关系。
        1. 图的邻接表存储有下面特点:
          1. 图的邻接表不是唯一的。因为在每个顶点对应的单链表中,各边结点的链接次序可以使任意的,这取决于建立邻接表的算法。
          2. 对于无向图,邻接表的顶点vi对应的链表长度正好顶点vi的度。
          3. 对于有向图,邻接表的顶点vi对应的链表长度正好顶点vi的出度。
          4. 对于有n个顶点,e条边的无向图,其邻接表有n个顶点和2e条边结点。在总边数小于n(n-1)/2时,邻接表比邻接矩阵要节省空间。
    3. 图的遍历
      1. 深度优先搜索
        基本思想:首先访问出发顶点v0,接着选择一个与vo相邻的,且没有被访问过的顶点w访问之,再从w开始进行深度优先搜索。直到达到一个顶点,其所有的邻接点都已被访问过;就从最后所访问的顶点开始,依次退回到尚有邻接点未访问的顶点u,并从u开始进行深度优先搜索。直到所有顶点都被访问过,或者从任何一个已访问顶点出发,再也无法达到未曾访问的顶点,则搜索结束。
        深度优先搜索法是一个递归过程,因此易于采用递归程序实现。
      2. 广度优先搜索
        基本思想:首先访问出发顶点v,然后访问顶点v的全部未访问过的邻接点w0、w1、w2、w3......wn,然后按照w0、w1、w2、w3......wn的次序,访问每个顶点的所有未被访问过的邻接点,依次类推,直到图中所有和初始顶点v有路径连通的顶点都被访问过为止。
        在使用广度优先搜索遍历图的时候,需要使用一个队列,以记录访问过的顶点。除出发顶点外,每次都取出队首顶点进行访问。每访问一个顶点,就将其加入队尾;利用队的先进先出特性,实现对邻接顶点访问次序的管理。
    4. 生成树和最小树
      1. 生成树
        设G是一个连通无向图,若G'是包含G所有顶点的无回路的连通子图,则称G'是G的一颗生成树
        (具有n个顶点的连通图至少有n-1条边,而生成树就正好只有n-1条边。
        在生成树中,任意加一条边,就会形成回路。)
        如果采用深度优先搜索法对连通无向图G进行遍历,则遍历产生的生成树是G的一颗DFS生成树;(depth深度)
        如果采用广度优先搜索法对连通无向图G进行遍历,则遍历产生的生成树是G的一颗BFS生成树。(breadth广度)
      2. 最小树:如果图的每条边都对应一个数值,具有边上权值最小的生成树称为图的最小生成树。
        1. Prim算法(个人总结的步骤)
          思想:从顶点出发
          1. 步骤:设G=(V,E)为带权连通无向图,图的顶点集合为V,边集合为E。
            1. 设顶点集合V '是一个空集合,边集合E '是一个空集合。
            2. 任意选取一个顶点v0,将v0加入V ',找出以v0为端点且权值最小的边e1(E包含e1,E '不包含e1),另一个端点为v1,将v1加入V ',将e1加入E ';
            3. 找出以V '集合中的顶点为端点且权值最小的边e2(E包含e2,E '不包含e2),另一个端点为v2,将v2加入V  ',将e2加入E ';
            4. 重复第三步骤,直到V ' 中包含了V中所有的顶点,即V '= V为止。
            5. 此事所有权值最小的边组成的树就是最小生成树。
          2. Prim算法总结
            1. 贪婪算法
        2. Kruskal算法(个人总结的步骤)
          思想:从边出发
          1. 步骤:设G=(V,E)为带权连通无向图,图的顶点集合为V,边集合为E。
            1. 设顶点集合V '包含V中所有顶点,边集合E '是一个空集合。
            2. 选权值最低的一条边e1,将其加入到E '中。
            3. 选权值最低的一条边e2(E包含e2,E '不含e2),且e2加入E '后不会使用V '中引入一个环(回路),可以称e2是安全边
            4. 重复第三步骤,直到V '中的顶点完全连通。
          2. Kruskal算法总结
            1. Kruskal算法属于一种贪心策略,由于Kruskal算法每次加入E '的边是安全边中权值最小的,所以可以保证通过Kruskal算法得到的生成树是带权连通无向图的最小树。
              需要指出的是,通过Kruskal算法得到的生成树不是唯一的(因为有权值相同的边都是安全边),但是所有最小生成树的网络代价是相同的。
    5. 图的应用
      1. 拓扑排序(一)
      2. 拓扑排序(二)
      3. 关键路径(一)
      4. 关键路经(二)
  8. 排序
    1. 插入排序
    2. 选择排序
    3. 快速排序(分治)
    4. 合并排序(分治)
    5. 基数排序
    6. 计数排序
    7. 桶排序
    8. 分治、树形、分配排序方法
  9. 查找
    1. 查找的基本概念
    2. 线性表的查找
      1. 顺序查找
      2. 二分查找
      3. 分块查找
    3. 树结构的查找
      1. 二叉查找树
        1. 由来
          在线性表的查找中,二分查找是一种高效的查找方法。但是,为了使用二分查找方法,线性表必须是有序表,且顺序存储。若线性表的结点需要经常进行插入和删除操作,顺序存储就相当不方便。那么,二叉查找树就由此而生。
        2. 概念:对于二叉树中的每个结点,其值大于左子树的所有节点的值,小于右子树的所有节点的值,这样的二叉树称为二叉查找树。
        3. 算法
          1. 插入操作
            首先要从根节点开始往下找到自己要插入的位置(即新节点的父节点);
            具体流程是:
            新节点与当前节点比较,如果相同则表示已经存在且不能再重复插入;
            如果小于当前节点,则到左子树中寻找,如果左子树为空则当前节点为要找的父节点,新节点插入到当前节点的左子树即可;
            如果大于当前节点,则到右子树中寻找,如果右子树为空则当前节点为要找的父节点,新节点插入到当前节点的右子树即可。
            开头:数据结构和算法_第1张图片
          2. 删除操作
            删除操作主要分为三种情况,即要删除的节点无子节点,要删除的节点只有一个子节点,要删除的节点有两个子节点。
            1.  对于要删除的节点无子节点可以直接删除,即让其父节点将该子节点置空即可。
            2.  对于要删除的节点只有一个子节点,则替换要删除的节点为其子节点。
            3.  对于要删除的节点有两个子节点,则首先找该节点的替换节点(即右子树中最小的节点,因为其其没有左孩子结点,替换方便),接着替换要删除的节点为替换节点,然后删除替换节点。
            开头:数据结构和算法_第2张图片
          3. 查询操作
            先和根节点比较,如果相同就返回,如果小于根节点则到左子树中递归查找,如果大于根节点则到右子树中递归查找。因此在排序二叉树中可以很容易获取最大(最右最深子节点)和最小(最左最深子节点)值。
        4. Java实现二叉排序树:Java实现二叉查找树
      2. 平衡的二叉排序树(又称AVL树)
        1. 平衡二叉树
          1. 由来:对一棵查找树进行查询/新增/删除 等动作, 所花的时间与树的高度h 成比例, 并不与树的容量 n 成比例。如果可以让树维持矮矮胖胖的好身材, 也就是让h维持在O(lg n)左右, 完成上述工作就很省时间。能够一直维持好身材, 不因新增删除而长歪的搜寻树, 叫做balanced search tree(平衡树)。
          2. 性质:一颗平衡二叉树,如果有n个结点,其高度可保持O(log2^n),平均搜索长度也可以保持在O(log2^n)
          3. 主要算法:平衡二叉树的常用算法有AVL、红黑树、Treap、伸展树、SBT等。
          4. 定义平衡二叉树
            定义二叉树的高度。设T是一颗二叉树,那么记号h(T)表示树T的高度。如果T是一颗空的二叉树,那么h(T)=-1;如果只有根结点,那么h(T)=0;如果T是一颗非空二叉树,Tl和Tr分别是T的根结点的左子树和右子树,那么h(T)=max{h(Tl),h(Tr)}+1。(也就是说树的高度=左、右子树中最大的高度+1)。
            定义二叉树的平衡因子。设k是二叉树的T的结点,Tkl和Tkr分别是结点k的左子树和右子树,那么结点k的平衡因子为bf(k)=h(Tkr)-(Tkl)。(也就是说k结点的平衡因子=右结点的高度-左结点的高度)
            如果二叉树T中任意结点k,都有| bf(k)|<=1,即所有结点的右子树和左子树的高度最多相差1,那么称T是一棵平衡二叉树
          5. 例如:
            注意平衡二叉树不是平衡的二叉排序树,但是平衡的二叉排序树是平衡二叉树
            开头:数据结构和算法_第3张图片
          6. 平衡树四种不平衡的情况及解决方法
            1. 第一种类型是由于在子树根节点的“”子结点的“”子树上插入结点,导致子树根节点的平衡因子由-1变成了-2,从而使平衡二叉树失去了平衡,这种类型称为LL型
              开头:数据结构和算法_第4张图片
            2. 第二种类型是由于在子树根节点的“左”子结点的“右”子树上插入结点,导致子树根节点的平衡因子由-1变成了-2,从而使平衡二叉树失去了平衡,这种类型称为LR型
              开头:数据结构和算法_第5张图片
            3. 第三种类型是由于在子树根节点的“右”子结点的“左”子树上插入结点,导致子树根节点的平衡因子由1变成了2,从而使平衡二叉树失去了平衡,这种类型称为RL型
              开头:数据结构和算法_第6张图片
            4. 第四种类型是由于在子树根节点的“右”子结点的“右”子树上插入结点,导致子树根节点的平衡因子由1变成了2,从而使平衡二叉树失去了平衡,这种类型称为LL型
              开头:数据结构和算法_第7张图片
            5. 上述四种类型中,第一种和第四种是对称的一组,它们的特点是在于子树的外侧发生变化而造成不平衡,称其为“外侧组”;而第二组和第三组是对称的另一组,它们是由于子树的内侧发生变化,称其为“内测组”。
        2. 概念:每个结点的左右树的高度差不超过1(也就是平衡二叉树)的二叉查找树,称为平衡二叉排序树
          例如:
          开头:数据结构和算法_第8张图片
          该二叉树,根结点的右子树高度为3,左子树高度为2。结点上方的数字为平衡因子,因为右子树高度比左子树高度大1,所以根结点的平衡因子为1。
        3. 平衡二叉排序树插入元素维持平衡的方法(如下是一个完整的例子)
          1. 单旋转
            1. 二叉右旋
              开头:数据结构和算法_第9张图片
            2. 二叉左旋
              开头:数据结构和算法_第10张图片
              开头:数据结构和算法_第11张图片
              开头:数据结构和算法_第12张图片
          2. 双旋转
            1. 先右后左双旋转
              开头:数据结构和算法_第13张图片
              开头:数据结构和算法_第14张图片
              开头:数据结构和算法_第15张图片
              开头:数据结构和算法_第16张图片
              开头:数据结构和算法_第17张图片
              开头:数据结构和算法_第18张图片
              开头:数据结构和算法_第19张图片
            2. 先左后右双旋转
              开头:数据结构和算法_第20张图片
        4. 算法
          1. 插入:平衡查找树维持平衡的例子,如上
          2. 删除:和插入没有本质区别,都是通过左旋或者右旋来完成。
          3. 查询:和二叉查找树查找方法相同
          4. 总结:平衡的二叉排序树查找的时间复杂度为O(log2^n)。那么插入和删除操作呢?
        5. Java代码实现平衡二叉排序树:Java实现平衡二叉排序树
    4. 散列方法
      1. 散列表
  10. 文件
    1. 文件
      1. 文件概念
        文件:通常称存储在外存储器中的记录为文件。是由大量性质相同的记录组成的集合。可按其记录的类型不同分为两类:操作系统文件和数据库文件
        记录
        定长记录文件、不定长记录文件
        单关键字文件、多关键字文件
        记录的逻辑结构、记录的物理结构
      2. 文件操作:检索和修改(插入、删除、更新)
        文件的操作可以有实时和批量两种不同的方式。
    2. 存取方法
      1. 顺序存储
        1. 顺序文件:指记录按建立该文件时的先后次序(逻辑顺序)一次存放在外存储器上。即顺序文件中物理记录的顺序和逻辑记录是一致的。
        2. 特点:由于顺序文件是连续存取速度快,因此主要用于顺序存储、批量修改等情况。
        3. 磁带就是一种典型的顺序存取设备,因此存储在磁带上的文件只能是顺序文件。
        4. 顺序文件的检索和修改(插入、删除、更新)
      2. 随机存储
        1. 索引文件
          1. 概念:
            索引表中的每一项称为索引项,索引项由记录和的关键字和记录的存放地址构成。
            索引表和主文件总称为索引文件。比如:图书资料索引、词典索引等
            索引表通常按键值的升序(递增次序)排序的。若主文件也按键值升序排列,则这样构成的索引文件称为索引顺序文件;若主文件是无序的所构成的索引文件称为索引无序文件
          2. 索引文件的存储
            索引顺序文件中,通常不是对主文件中每一个记录都设置一个索引项,而是将主文件分成若干块,然后把每块中最大键值和该块的起始地址组成一个索引项。再把所有索引项按键值升序排列组成索引表。索引表本身也可看成是主文件,可再建立高一级的索引表,以提高查找效率。如果需要,还可建立高级的索引表......。各级索引表和主文件一起构成索引顺序文件

            有时主文件采用顺序文件组织形式很不方便,因为在形成文件,其记录并不一定按主关键字值升序来,如果记录按到达时间顺序排列,就形成一个无序文件。为了加快查找速度,可以把每个记录的键值及记录的开始地址构造索引项,再把所有的索引项按键值升序排列并将其共视为顺序文件,按索引顺序文件方法对他建立各级索引,构成索引无序文件。索引无序文件仅适用于随机存取。

            索引表本身可以用多种方法进行组织,入多级索引、散列索引、B树索引等。由于B树能动态地维持树的平衡,查询速度快,仅介绍用B树以其变种B+树组织索引的方法
          3. 索引文件的检索和修改(插入、删除、更新)
            1. B-树(B树)
              1. 概念
                平衡的多路查找树。每一个节点即存储了索引又存储了数据。
            2. B+树
              1. 由来:B+树是通过二叉查找树,再由平衡二叉树,B树演化而来的,在组织索引文件时比B树更常用。
              2. 概念
                平衡的多路查找树。数据只存储在叶子节点。、
              3. 算法
                1. 插入
                2. 删除
                3. 检索
                4. 更新
          4. 索引顺序文件
            1. ISAM文件
              1. 索引顺序存取方法是一种专门为磁盘存取设计的文件组织方式。由于磁盘是以盘组、柱面和磁道三级地址存取的设备,则可对磁盘上的数据文件建立盘组、柱面和磁道三级索引。文件的记录在同一盘组上存取时,应先放在一个柱面上,然后再顺序存放在相邻的柱面上,对同一个柱面,则应按盘面的次序顺序存放。
          5. 多关键字文件
            特点:在对文件进行检索操作时,不仅对主关键字进行简单询问,还经常需要对次关键字进行其他类型的询问检索。
            1. 多重文件
            2. 倒排文件
        2. 散列文件
          1. 散列文件是指利用Hash法进行组织的文件。它类似于散列表,即根据文件中关键字的特点设计一种散列函数处理冲突的方法将记录散列到存储设备上。
          2. 散列文件的存储
                   与散列表不同的是,对于文件来说,磁盘上的文件记录通常是成组存放的。若干个记录组成一个存储单位,在散列文件中,这个存储单位叫做桶(Bucket).假若一个桶能存放m个记录,这就是说,m个同义词的记录可以存放在同一个地址的桶中,而当第m+1个同义词出现时发生“溢出”。处理溢出也可采用散列表中处理冲突的各种方法,但对散列文件,主要采用链地址法
                   当发生“溢出”时,需要将第m+1个同义词存放到另一个桶中,统常称此桶为“溢出桶”;相对的,称前m个同义词存放的桶为‘基桶’。溢出桶和基桶大小相同,相互之间指针链接。当在基桶中没有找到待查记录时,就顺时针指到溢出桶中进行查找。因此,希望同一散列地址的溢出桶和基桶在磁盘上的物理位置不要相距太远,最好在同一个柱面上
          3. 散列文件的操作
            1. 查找
            2. 删除
            3. 修改
  11. 中级

  12. 高级数据结构
    1. 并查集:不相交集类
    2. 树状数组
    3. 线段树
    4. 倍增、ST表
    5. 算法之RMO和LCA
    6. Treap树
    7. 树链剖分
    8. 哈希树:一种持久性数据结构,可用于实现集合和映射,旨在替换纯函数式编程中的哈希表。 在其基本形式中,哈希树在trie中存储其键的哈希值(被视为位串),其中实际键和(可选)值存储在trie的“最终”节点中
    9. 字典树:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。
      典型应用是用于统计,排序和保存大量的字符(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
      它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
      Trie的核心思想是空间换时间
    10. 后缀树、后缀数组
      1. 后缀树:后缀树提出的目的是用来支持有效的字符串匹配和查询。
      2. 后缀数组:在字符串处理当中,后缀树和后缀数组都是非常有力的工具。其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间复杂度也不太逊色,并且,它比后缀树所占用的空间小很多。可以说,在信息学竞赛中后缀数组比后缀树要更为实用。
    11. 分块
    12. 点分治
    13. 边分治
    14. AC自动机
    15. 红黑树
      1. 概念
        红黑树是一种平衡二叉查找树(AVL树)的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但 对之进行平衡的代价较低, 其平均统计性能要强于 AVL 。 
        由于每一颗红黑树都是一颗二叉排序树,所以红黑树上的只读操行与普通二叉查找树相同。
      2. 性质
        红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。
        1. 性质1. 节点是红色或黑色。
        2. 性质2. 根节点是黑色。
        3. 性质3. 所有叶子都是黑色。(叶子是NULL节点)
        4. 性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
        5. 性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

          这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。 
          是性质4导致路径上不能有两个连续的红色节点确保了这个结果。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。
      3. 算法
        1. 查询:与普通二叉查找树相同
        2. 插入:插入操作是最关键的,为了维持平衡和符合红黑树的性质,可以采用两个操作应对:变色和树的旋转(左旋转和右旋转)
        3. 删除
      4. 对比:经验指出,平均红黑树大约和平均AVL树一样深,从而查找时间一般接近最优。红黑树的优点是执行插入所需要的开销相对较低,另外就是实践中发生的旋转相对较少。
      5. 应用
        1. java中的TreeSet、TreeMap的底层都是红黑树,Java8中的HashMap解决冲突也是采用红黑树。
    16. 伸展树
    17. K-D树
    18. 动态树
    19. 左偏树(可合并堆)
    20. SB树
    21. SBT树
    22. 跳表:二分查找查找快,但是添加和删除速度慢,那么怎样可以做到查找、添加、删除速度都快呢?那么选择跳表
      1. 跳表与二分查找
    23. 树套树
    24. 可持久化数据结构
  13. 算法设计技巧
    1. 贪心算法
      1. 背包问题
    2. 动态规划DP
      1. 线性DP
      2. 最长公共子序列、最长上升子序列
      3. 树形DP
      4. 背包类树形DP
      5. 区间DP
      6. 矩阵连乘、石子合并
      7. 数位DP
      8. 数字游戏
      9. 状态压缩DP
      10. 旅行商
      11. 接头DP
    3. 动态规划优化
      1. 倍增优化
      2. 数据结构优化
      3. 单调队列优化
      4. 斜率优化
      5. 四边不等式优化
    4. 深度搜索应用
      1. 回溯法
      2. 01背包
      3. 地图着色
      4. n皇后
      5. 最优加工顺序
    5. 广度搜索应用
      1. 01背包
      2. 旅行商问题
  14. 高级

    1. 启发式搜索
      1. A*搜索
    2. 最大流
      1. 最短增广路算法
      2. Dinic算法
    3. 最大流改进算法
      1. 标签算法ISPA
    4. 二分图最大匹配
      1. 配对方案
      2. 匈牙利算法
    5. 最大流最小割
      1. 最大收益
      2. 方格取数
    6. 最小费用最大流
      1. 最小费用路算法
      2. 消圈算法

你可能感兴趣的:(数据结构与算法)