2024王道数据结构考研丨第五篇:树、图

news2025/1/13 13:11:25

2024王道数据结构考研笔记专栏将持续更新,欢迎 点此 收藏,共同交流学习…

文章目录

  • 第五章:树
      • 5.1树的基本概念
        • 5.1.1树的定义
        • 5.1.2基本术语
        • 5.1.3树的性质
      • 5.2二叉树的概念
        • 5.2.1 二叉树的定义与特性
        • 5.2.2几种特殊的二叉树
        • 5.2.3二叉树的存储结构
      • 5.3二叉树的遍历和线索二叉树
        • 5.3.1二叉树的遍历
        • 5.3.2线索二叉树
      • 5.4树、森林
        • 5.4.1树的存储结构
        • 5.4.2树、森林与二叉树的转换
        • 5.4.3树、森林的遍历
      • 5.5树与二叉树的应用
        • 5.5.1二叉排序树(BST)
        • 5.5.2平衡二叉树(AVL)
      • 5.5.3哈夫曼树
  • 第六章 图
      • 6.1图的基本概念
      • 6.2图的存储结构
        • 6.2.1数组表示法(邻接矩阵表示法)
        • 6.2.2 邻接表(类似于数的孩子链表表示法)
        • 6.2.3十字链表
      • 6.3图的遍历
      • 6.4最小生成树
      • 6.5最短路径
      • 6.6AOV网络与拓扑排序
      • 6.7 AOE网络与关键路径

第五章:树

5.1树的基本概念

5.1.1树的定义

树是n个结点的有限集。

  • 空树:n=0
  • 根结点、分支结点、叶子结点
  • 非空树的特性
  • 子树

5.1.2基本术语

  1. 结点之间的关系描述
    1. 祖先、子孙、双亲、兄弟…结点
    2. 路径、路径长度
  2. 结点、树的属性描述
    1. 结点的层次(深度)——从上往下
    2. 结点的高度——从下往上
    3. 树的高度——总共多少层
    4. 结点的度——有几个孩子
    5. 树的度——各结点的度的最大值
  3. 有序树、无序树
  4. 森林

5.1.3树的性质

  1. 树中的结点数等于所有结点的度数之和加1。
  2. 度为m的树第i层上至多有m^i-1个结点
  3. 度为m的数、m叉数的区别
    在这里插入图片描述

5.2二叉树的概念

5.2.1 二叉树的定义与特性

定义:
二叉树是n(n>=0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两颗互不相交的分别称作这个根的左子树和右子树的二叉树组成。

特点:

  1. 每个结点最多有俩孩子(二叉树中不存在度大于2的结点)。
  2. 二叉树可以是空集合,根可以有空的左子树和空的右子树。
  3. 二叉树有左右之分,次序不能颠倒。

二叉树的性质:

  1. 在二叉树的第i层上至多有2^(i-1)个结点(i>1)。

  2. 深度为k的二叉树至多有2^k-1个结点(k>=1)。

  3. 对任何一颗二叉树T,如果其叶子数为n0,度为2的结点数为n2,则n0=n2+1.

  4. 具有n个结点的完全二叉树的深度为(log2N)+1。
    在这里插入图片描述

注意:二叉树不是树的特殊情况,它们是两个概念。

5.2.2几种特殊的二叉树

  1. 满二叉树:一颗深度为k且有2^k-1个结点的二叉树称为满二叉树。每一层上的结点数都达到最大。叶子全部在最低层。
  2. 完全二叉树:深度为k的具有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号为1~n的结点一 一对应时,称之为完全二叉树。
  3. 二叉排序树
  4. 平衡二叉树

5.2.3二叉树的存储结构

  1. 顺序存储
    二叉树的顺序存储中,一定要把二叉树的结点编号与完全二叉树对应起来;
#define MaxSize 100

struct TreeNode{
   ElemType value; //结点中的数据元素
   bool isEmpty;   //结点是否为空
}

main(){
   TreeNode t[MaxSize];
   for (int i=0; i<MaxSize; i++){
      t[i].isEmpty = true;
   }
}

  1. 链式存储
//二叉树的结点

struct ElemType{
   int value;
};

typedef struct BiTnode{
   ElemType data;          //数据域
   struct BiTNode *lchild, *rchild; //左、右孩子指针
}BiTNode, *BiTree;

//定义一棵空树
BiTree root = NULL;

//插入根节点
root = (BiTree) malloc (sizeof(BiTNode));
root -> data = {1};
root -> lchild = NULL;
root -> rchild = NULL;

//插入新结点
BiTNode *p = (BiTree) malloc (sizeof(BiTNode));
p -> data = {2};
p -> lchild = NULL;
p -> rchild = NULL;
root -> lchild = p; //作为根节点的左孩子

  • 找到指定结点p的左/右孩子;
  • 找到指定结点p的父节点;只能从根结点开始遍历,也可以使用三叉链表
typedef struct BiTnode{
   ElemType data;          //数据域
   struct BiTNode *lchild, *rchild; //左、右孩子指针
   struct BiTNode *parent;          //父节点指针
}BiTNode, *BiTree;

  • n个结点的二叉链表共有n+1个空链域

5.3二叉树的遍历和线索二叉树

5.3.1二叉树的遍历

  1. 先序遍历(根左右)
  • 若二叉树为空,不用操作
  • 若二叉树非空:
    • 访问根节点
    • 先序遍历左子树
    • 先序遍历右子树
typedef struct BiTnode{
   ElemType data;          
   struct BiTNode *lchild, *rchild; 
}BiTNode, *BiTree;

void PreOrder(BiTree T){
   if(T!=NULL){
      visit(T);                 //访问根结点
      PreOrder(T->lchild);      //递归遍历左子树
      PreOrder(T->rchild);      //递归遍历右子树
   }
}

  1. 中序遍历(左根右)
  • 若二叉树为空,不用操作
  • 若二叉树非空:
    • 先序遍历左子树
    • 访问根节点
    • 先序遍历右子树
typedef struct BiTnode{
   ElemType data;          
   struct BiTNode *lchild, *rchild; 
}BiTNode, *BiTree;

void InOrder(BiTree T){
   if(T!=NULL){
      InOrder(T->lchild);       //递归遍历左子树
      visit(T);                 //访问根结点
      InOrder(T->rchild);       //递归遍历右子树
   }
}

  1. 后续遍历(左右根)
  • 若二叉树为空,不用操作
  • 若二叉树非空:
    - 先序遍历左子树
    - 先序遍历右子树
    - 访问根节点
typedef struct BiTnode{
   ElemType data;          
   struct BiTNode *lchild, *rchild; 
}BiTNode, *BiTree;

void PostOrder(BiTree T){
   if(T!=NULL){
      PostOrder(T->lchild);       //递归遍历左子树    
      PostOrder(T->rchild);       //递归遍历右子树
      visit(T);                 //访问根结点
   }
}

  1. 二叉树的层次遍历
    算法思想:
  • 初始化一个辅助队列
  • 根节点入队
  • 若队列非空,则队头结点出队,访问该结点,依次将其左、右孩子插入队尾(如果有的话)
  • 重复以上操作直至队列为空
//二叉树的结点(链式存储)
typedef struct BiTnode{
   ElemType data;          
   struct BiTNode *lchild, *rchild; 
}BiTNode, *BiTree;

//链式队列结点
typedef struct LinkNode{
   BiTNode * data;
   typedef LinkNode *next;
}LinkNode;

typedef struct{
   LinkNode *front, *rear;  
}LinkQueue;

//层序遍历
void LevelOrder(BiTree T){
   LinkQueue Q;
   InitQueue (Q);          //初始化辅助队列
   BiTree p;
   EnQueue(Q,T);           //将根节点入队
   while(!isEmpty(Q)){     //队列不空则循环
      DeQueue(Q,p);        //队头结点出队
      visit(p);            //访问出队结点
      if(p->lchild != NULL)
         EnQueue(Q,p->lchild);   //左孩子入队
      if(p->rchild != NULL)
         EnQueue(Q,p->rchild);   //右孩子入队
   }
}

  1. 由遍历序列构造二叉树
  • 先序序列 + 中序序列
  • 后序序列 + 中序序列
  • 层序序列 + 中序序列
    key: 找到树的根节点,并根据中序序列划分左右子树,再找到左右子树根节点、

5.3.2线索二叉树

  1. 线索二叉树的概念与作用
    在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化。
  2. 线索二叉树的存储结构
  • 中序线索二叉树——线索指向中序前驱、中序后继
//线索二叉树结点
typedef struct ThreadNode{
   ElemType data;
   struct ThreadNode *lchild, *rchild;
   int ltag, rtag;                // 左、右线索标志
}ThreadNode, *ThreadTree;


tag == 0: 指针指向孩子

tag == 1: 指针是“线索”

  • 先序线索二叉树——线索指向先序前驱、先序后继

  • 后序线索二叉树——线索指向后序前驱、后序后继

  1. 二叉树的线索话
  • 中序线索化
typedef struct ThreadNode{
   int data;
   struct ThreadNode *lchild, *rchild;
   int ltag, rtag;                // 左、右线索标志
}ThreadNode, *ThreadTree;

//全局变量pre, 指向当前访问的结点的前驱
TreadNode *pre=NULL;

void InThread(ThreadTree T){
    if(T!=NULL){
        InThread(T->lchild);    //中序遍历左子树
        visit(T);               //访问根节点
        InThread(T->rchild);    //中序遍历右子树
    }
}

void visit(ThreadNode *q){
   if(q->lchid = NULL){                 //左子树为空,建立前驱线索   
      q->lchild = pre;
      q->ltag = 1;
   }

   if(pre!=NULL && pre->rchild = NULL){ 
      pre->rchild = q;           //建立前驱结点的后继线索
      pre->rtag = 1;
   }
   pre = q;
}

//中序线索化二叉树T
void CreateInThread(ThreadTree T){
   pre = NULL;                //pre初始为NULL
   if(T!=NULL);{              //非空二叉树才能进行线索化
      InThread(T);            //中序线索化二叉树
      if(pre->rchild == NULL)
         pre->rtag=1;         //处理遍历的最后一个结点
   }
}


  • 先序线索化
    注意【转圈】问题,当ltag==0时,才能对左子树先序线索化
typedef struct ThreadNode{
   int data;
   struct ThreadNode *lchild, *rchild;
   int ltag, rtag;                // 左、右线索标志
}ThreadNode, *ThreadTree;

//全局变量pre, 指向当前访问的结点的前驱
TreadNode *pre=NULL;

//先序遍历二叉树,一边遍历一边线索化
void PreThread(ThreadTree T){
   if(T!=NULL){
      visit(T);
      if(T->ltag == 0)         //lchild不是前驱线索
         PreThread(T->lchild);
      PreThread(T->rchild);
   }
}

void visit(ThreadNode *q){
   if(q->lchid = NULL){                 //左子树为空,建立前驱线索   
      q->lchild = pre;
      q->ltag = 1;
   }

   if(pre!=NULL && pre->rchild = NULL){ 
      pre->rchild = q;           //建立前驱结点的后继线索
      pre->rtag = 1;
   }
   pre = q;
}

//先序线索化二叉树T
void CreateInThread(ThreadTree T){
   pre = NULL;                //pre初始为NULL
   if(T!=NULL);{              //非空二叉树才能进行线索化
      PreThread(T);            //先序线索化二叉树
      if(pre->rchild == NULL)
         pre->rtag=1;         //处理遍历的最后一个结点
   }
}

  • 后序线索化
typedef struct ThreadNode{
   int data;
   struct ThreadNode *lchild, *rchild;
   int ltag, rtag;                // 左、右线索标志
}ThreadNode, *ThreadTree;

//全局变量pre, 指向当前访问的结点的前驱
TreadNode *pre=NULL;

//先序遍历二叉树,一边遍历一边线索化
void PostThread(ThreadTree T){
   if(T!=NULL){
      PostThread(T->lchild);
      PostThread(T->rchild);
      visit(T);                  //访问根节点
   }
}

void visit(ThreadNode *q){
   if(q->lchid = NULL){                 //左子树为空,建立前驱线索   
      q->lchild = pre;
      q->ltag = 1;
   }

   if(pre!=NULL && pre->rchild = NULL){ 
      pre->rchild = q;           //建立前驱结点的后继线索
      pre->rtag = 1;
   }
   pre = q;
}

//先序线索化二叉树T
void CreateInThread(ThreadTree T){
   pre = NULL;                //pre初始为NULL
   if(T!=NULL);{              //非空二叉树才能进行线索化
      PostThread(T);            //后序线索化二叉树
      if(pre->rchild == NULL)
         pre->rtag=1;         //处理遍历的最后一个结点
   }
}

  1. 线索二叉树中找前驱、后继
  • 中序线索二叉树找中序后继:在中序线索二叉树中找到指定节点 *p 的中序后继 next
若 p->rtag == 1, 则 next = p->rchild;

若 p->rtag == 0, 则 p 必有右孩子, 则 next = p的右子树中最左下结点;
//1. 找到以P为根的子树中,第一个被中序遍历的结点
ThreadNode *Firstnode(ThreadNode *p){
   //循环找到最左下的结点(不一定是叶结点)
   while(p->ltag == 0)
      p=p->lchild;
   return p;
}

//2. 在中序线索二叉树中找到结点p的后继结点
ThreadNode *Nextnode(ThreadNode *p){
   //右子树最左下结点
   if(p->rtag==0)
      return Firstnode(p->rchild);
   else 
      return p->rchild; //rtag==1,直接返回后继线索
}

//3. 对中序线索二叉树进行中序遍历
void Inorder(ThreadNode *T){            //T为根节点指针
   for(ThreadNode *p = Firstnode(T); p!=NULL; p = Nextnode(p))
      visit(p);
}

  • 先序线索二叉树找先序后继:在先序线索二叉树中找到指定节点 *p 的先序后继 next

p->rtag == 1, 则 next = p->rchild; 若 p->rtag == 0, 则 p 必有右孩子(左孩子不知道)

case1: 若p有左孩子 ——— 根 左 右 / 根 (根 左 右) 右

case2: 若p没有左孩子 ——— 根 右 / 根 (*根 *左 右)

  • 先序线索二叉树找先序前驱:在先序线索二叉树中找到指定节点 *p 的先序前驱pre

若 p->ltag == 1, 则 next = p->lchild;

若 p->ltag == 0, 则 p
必有左孩子,但是先序遍历中,左右子树的结点只可能是根的后继,不可能是前驱,所以不能从左右孩子里寻找p的先序前驱,(除非从头开始遍历/三叉链表

case1: 如果能够找到p的父节点,且p是左孩子 —— p的父节点就是p的前驱;

case2: 如果能够找到p的父节点,且p是右孩子,且其左兄弟为空 —— p的父节点就是p的前驱;

case3: 如果能够找到p的父节点,且p是右孩子,且其左兄弟非空 ——
p的前驱为左兄弟子树中最后一个被先序遍历到的结点(根节点出发,先往右,右没有往左,找到最下一层的结点);

case4: p没有父节点,即p为根节点,则p没有先序前驱

  • 后序线索二叉树找后序前驱:在后序线索二叉树中找到指定节点 *p 的后序前驱pre

若 p->ltag == 1, 则 next = p->lchild;

若 p->ltag == 0, 则 p 必有左孩子(不知道有没有右孩子)

case1: 若p有右孩子 ——— 左 右 根 / 左 (左 右 根) 根

case2: 若p没有右孩子 ——— 左 根 (左子树按后序遍历,最后一个结点,p的左孩子)

  • 后序线索二叉树找后序后继:在后序线索二叉树中找到指定节点 *p 的后序后继next

若 p->rtag == 1, 则 next = p->rchild;

若 p->rtag == 0, 则 p 必有右孩子, 左孩子不知道, 但是在后序遍历中,左右子树中的结点只有可能是根的前驱,而不可能是根的后继,所以找不到后继,(除非从头开始遍历/三叉链表

case1: 如果能找到p的父节点,且p是右孩子 —— p的父节点即为其后继

case2: 如果能找到p的父节点,且p是左孩子,其右兄弟为空 —— p的父节点即为其后继

case3: 如果能找到p的父节点,且p是左孩子,其右兄弟非空 —— p的后继为其右兄弟子树中第一个被后序遍历的结点;

case4: p没有父节点,即p为根节点,则p没有后序后继;

在这里插入图片描述

5.4树、森林

5.4.1树的存储结构

  1. 双亲表示法(顺序存储):每个结点中保存指向双亲的指针

数据域:存放结点本身信息。
双亲域:指示本结点的双亲结点在数组中的位置。

#define MAX_TREE_SIZE 100  //树中最多结点数

typedef struct{      //树的结点定义
   ElemType data; 
   int parent;      //双亲位置域
}PTNode;

typedef struct{                   //树的类型定义
   PTNode nodes[MAX_TREE_SIZE];   //双亲表示
   int n;                         //结点数
}PTree;

增:新增数据元素,无需按逻辑上的次序存储;(需要更改结点数n)
删(叶子结点):① 将伪指针域设置为-1;②用后面的数据填补;(需要更改结点数n)
查询:①优点-查指定结点的双亲很方便;②缺点-查指定结点的孩子只能从头遍历,空数据导致遍历更慢;

  1. 孩子表示法(顺序+链式)
    孩子链表:把每个结点的孩子结点排列起来,看成是一个线性表,用单链表存储,则n个结点有n个孩子链表(叶子的孩子链表为空表)。而n个头结点又组成一个线性表,用顺序表(含n个元素的结构数组)存储。
struct CTNode{
   int child;    //孩子结点在数组中的位置
   struct CTNode *next;    // 下一个孩子
};

typedef struct{
   ElemType data;
   struct CTNode *firstChild;    // 第一个孩子
}CTBox;

typedef struct{
   CTBox nodes[MAX_TREE_SIZE];
   int n, r;   // 结点数和根的位置
}CTree;

  1. 孩子兄弟表示法(链式)
typedef struct CSNode{
   ElemType data;                               //数据域
   struct CSNode *firstchild, *nextsibling;     //第一个孩子和右兄弟指针, *firstchild 看作左指针,*nextsibling看作右指针
}CSNode. *CSTree;

5.4.2树、森林与二叉树的转换

本质:森林中各个树的根结点之间视为兄弟关系

将树转换成二叉树:

  1. 加线:在兄弟之间加一连线
  2. 抹线:对每个结点去除其与孩子之间的关系(第一孩子除外)
  3. 旋转:以树的根结点为轴心,顺时针转45度
    (兄弟相连留长子)

5.4.3树、森林的遍历

  1. 树的遍历
  • 先根遍历:若树非空,先访问根结点,再依次对每棵子树进行先根遍历;(与对应二叉树的先序遍历序列相同)
void PreOrder(TreeNode *R){
   if(R!=NULL){
      visit(R);    //访问根节点
      while(R还有下一个子树T)
         PreOrder(T);      //先跟遍历下一个子树
   }
}

  • 后根遍历:若树非空,先依次对每棵子树进行后根遍历,最后再返回根节点;(与对应二叉树的中序遍历序列相同)
void PostOrder(TreeNode *R){
   if(R!=NULL){
      while(R还有下一个子树T)
         PostOrder(T);      //后跟遍历下一个子树
      visit(R);    //访问根节点
   }
}

  • 层序遍历(队列实现):

若树非空,则根结点入队;
若队列非空,队头元素出队并访问,同时将该元素的孩子依次入队;
重复以上操作直至队尾为空;

  1. 森林的遍历
  • 先序遍历:等同于依次对各个树进行先根遍历;也可以先转换成与之对应的二叉树,对二叉树进行先序遍历;
  • 中序遍历:等同于依次对各个树进行后根遍历;也可以先转换成与之对应的二叉树,对二叉树进行中序遍历;

5.5树与二叉树的应用

5.5.1二叉排序树(BST)

  1. 二叉排序树的定义
    左子树结点值<跟结点值<右子树结点值
  2. 查找操作
typedef struct BSTNode{
   int key;
   struct BSTNode *lchild, *rchild;
}BSTNode, *BSTree;

//在二叉排序树中查找值为key的结点(非递归)
//最坏空间复杂度:O(1)
BSTNode *BST_Search(BSTree T, int key){
   while(T!=NULL && key!=T->key){        //若树空或等于跟结点值,则结束循环
      if(key<T->key)       //值小于根结点值,在左子树上查找
         T = T->lchild;
      else                  //值大于根结点值,在右子树上查找
         T = T->rchild;
   }
   return T;
}

//在二叉排序树中查找值为key的结点(递归)
//最坏空间复杂度:O(h)
BSTNode *BSTSearch(BSTree T, int key){
   if(T == NULL)
      return NULL;
   if(Kry == T->key)
      return T;
   else if(key < T->key)
      return BSTSearch(T->lchild, key);
   else 
      return BSTSearch(T->rchild, key);
}

  1. 插入操作
//在二叉排序树中插入关键字为k的新结点(递归)
//最坏空间复杂度:O(h)
int BST_Insert(BSTree &T, int k){
   if(T==NULL){           //原树为空,新插入的结点为根结点
      T = (BSTree)malloc(sizeof(BSTNode));
      T->key = k;
      T->lchild = T->rchild = NULL;
      return 1;                       //插入成功
   }
   else if(K == T->key)               //树中存在相同关键字的结点,插入失败
      return 0;
   else if(k < T->key)                 
      return BST_Insert(T->lchild,k);
   else 
      return BST_Insert(T->rchild,k);
}

  1. 二叉排序树的构造
//按照str[]中的关键字序列建立二叉排序树
void Crear_BST(BSTree &T, int str[], int n){
   T = NULL;                     //初始时T为空树
   int i=0;
   while(i<n){
      BST_Insert(T,str[i]);     //依次将每个关键字插入到二叉排序树中
      i++;
   }
}

  1. 删除操作
  2. 查找效率分析

查找长度:查找运算中,需要对比关键字的次数,反映了查找操作时间复杂度;
查找成功的平均查找长度ASL
查找失败的平均查找长度ASL

5.5.2平衡二叉树(AVL)

  1. 平衡二叉树的定义
    在插入和删除二叉树的结点时,要保证任意结点的左右子树的高度差的绝对值不超过1,将这样的树称为平衡二叉树
//平衡二叉树结点
typedef struct AVLNode{
   int key;         //数据域
   int balance;     //平衡因子
   struct AVLNode *lchild; *rchild; 
}AVLNode, *AVLTree;


  1. 平衡二叉树的插入
  2. 插入新节点后如何调整“不平衡”问题
    调整最小不平衡子树

LL: 在A结点的左孩子的左子树中插入导致不平衡
调整: A的左孩子结点右上旋
RR: 在A结点的右孩子的右子树中插入导致不平衡
调整: A的右孩子结点左上旋
LR: 在A结点的左孩子的右子树中插入导致不平衡
调整: A的左孩子的右孩子,先左上旋再右上旋
RL: 在A结点的右孩子的左子树中插入导致不平衡
调整: A的右孩子的左孩子,先右上旋再左上旋

  1. 平衡二叉树的查找与效率分析
    若树高为h,则最坏情况下,查找一个关键字最多需要对比h次,即查找操作的时间复杂度不可能超过O(h);

5.5.3哈夫曼树

  1. 带权路径长度:从根节点到该结点之间的路径长度与该节点的权的乘积。
  2. 哈夫曼树的定义:带权路径最短的树。
  3. 哈夫曼树的构造(重点):构造森林全是根,选用两小造新树,删除两小添新人,重复2、3剩单根。
  4. 哈杜曼编码(重点):
    在这里插入图片描述

由哈夫曼树得到的二进制前缀编码称为哈夫曼编码。

第六章 图

6.1图的基本概念

  • 图是一种非线性结构
  • 图的特点:
  1. 顶点之间的关系是任意的
  2. 图中任意两个顶点之间都可能相关
  3. 顶点的前驱和后继个数无限制
  • 定义:图是一种数据元素间存在多对多关系的数据结构加上一组基本操作构成的抽象数据类型。
    生成树:所有顶点均由边连接在一起但不存在回路的图。

6.2图的存储结构

6.2.1数组表示法(邻接矩阵表示法)

在这里插入图片描述
在这里插入图片描述

6.2.2 邻接表(类似于数的孩子链表表示法)

在这里插入图片描述
在这里插入图片描述

6.2.3十字链表

在这里插入图片描述

6.3图的遍历

定义:从图的任意指定顶点出发,依照某种规则去访问图中所有顶点,且每个顶点仅被访问一次,这一过程叫图的遍历。
方式:

  • 深度优先遍历方法(Depth_First Search——DFS)
  • 广度优先遍历法(Breadth_Frist Search——BFS)

6.4最小生成树

普里姆(Prim)算法。
在这里插入图片描述

6.5最短路径

迪杰斯特拉:

在这里插入图片描述

6.6AOV网络与拓扑排序

6.7 AOE网络与关键路径


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/560606.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022级云曦实验室考试(一)reverse

一.Reverse 打开后是个rar压缩包&#xff0c;解压后 发现这玩意儿&#xff0c;我也不知道是个啥&#xff0c;之前没做过这类题 浅搜一下 啊&#xff0c;看不懂 用一下自己的歪办法 用txt打开看看有没有啥&#xff1f; 发现两个里面都有相同的flag&#xff0c;改成正确格式&…

C语言小游戏--三子棋

目录 问题描述 逻辑分析 具体实现 1.进入菜单界面 2.初始化棋盘 3.打印棋盘 4.玩家下棋 5.电脑下棋 6.判断输赢 运行结果 完整代码 game.h game.c test.c 问题描述 结合C语言所学知识&#xff0c;简单实现一个三子棋小游戏。 逻辑分析 进入菜单界面初始化棋盘…

帅地这些年看过的书

大家好&#xff0c;我是帅地。 好久没有给大家推荐书籍了&#xff0c;我一般很少给大家推荐书籍&#xff0c;因为自己没看过的&#xff0c;基本不推&#xff0c;只推荐我自己看过且自己自认为不错的书籍。 因为我自己本身是凭借着扎实的基础拿到大厂 offer 的&#xff0c;所以…

nodej+vues汽车销售4s店服务平台商城系统购物车积分兑换7z9d2

在经济快速发展的带动下&#xff0c;汽车服务平台的发展也是越来越快速。用户对汽车服务信息的获取需求很大。在互联网飞速发展的今天&#xff0c;制作一个汽车服务平台系统是非常必要的。本系统是借鉴其他人的开发基础上&#xff0c;用MySQL数据库和nodejs定制了汽车服务平台系…

Windows安装多个Mysql服务

1、正常安装好第一个 正常安装即可 2、第二个安装方法 1、官网下载zip包 MySQL :: MySQL Downloads 2、解压下载好的压缩包 &#xff08;注意修改文件夹名称&#xff0c;此时文件夹内并没有data文件夹&#xff09; 3、编写my.ini 注意修改端口号port以及安装目录basedir…

龙芯2K1000实战开发-平台介绍

文章目录 概要整体架构流程技术名词解释技术细节小结概要 龙芯 2K1000 处理器主要面向于网络应用,兼顾平板应用及工控领域应 用。采用 40nm 工艺,片内集成 2 个 GS264 处理器核,主频 1GHz,64 位 DDR3 控制器,以及各种系统 IO 接口。 整体架构 龙芯 2K1000 的结构如图 所…

《Oracle高级数据库》期末复习一文总结

文章目录 第一章&#xff1a;数据库基础1.数据库系统数据库数据库管理系统数据库系统 2.数据模型层次模型网状模型关系模型 3.关系型数据库&#xff08;1&#xff09;数据定义语言&#xff08;DDL&#xff09;&#xff08;2&#xff09;数据操纵语言&#xff08;DML&#xff09…

UC-OWOD: Unknown-Classified Open World Object Detection(论文翻译)

文章目录 UC-OWOD: Unknown-Classified Open World Object Detection摘要1.介绍2.相关工作3.未知分类的开放世界目标检测3.1 问题定义3.2 整体架构3.3 未知物体的检测3.4基于相似性的未知分类3.5未知聚类优化3.6训练和优化 4&#xff1a;实验4.1准备工作4.2结果和分析4.3消融研…

数学算法组合与排序

一句话总结&#xff1a;组合得次序是否重要&#xff0c;是否可重复&#xff0c;决定了组合数量 一、什么是组合&排序 组合可以是现实的一切事物、例如 [衣服&#xff0c;鞋子&#xff0c;眼镜...] 等等&#xff0c; 也可以表示一组数字 [1, 2, 3, 4, 5] &#xff0c;从个人…

STL常用容器_2

目录 一、stcak容器&#xff08;栈容器&#xff09; 1、基本概念 2、常用接口 二、queue容器&#xff08;队列容器&#xff09; 1、基本概念 2、常用接口函数 三、list容器&#xff08;链表&#xff09; 1、基本概念 2、构造函数 3、赋值与交换 4、大小操作 5、插入…

网络层和数据链路层

目录 网络层 IP协议 基本概念 协议头格式 ​编辑 网段划分 特殊的IP地址 IP地址的数量限制 私有IP地址和公网IP地址 路由 ​编辑数据链路层 以太网 以太网帧格式 认识MAC地址 对比理解MAC地址和IP地址 认识MTU MTU对IP协议的影响 ​编辑 MTU对UDP协议的影响 …

新产品上线前需要准备哪些产品文档呢

新产品上线前需要准备的产品文档非常重要&#xff0c;不仅有助于产品的开发过程中沟通和协作&#xff0c;而且对于后期的维护和升级也起到十分重要的作用。下面详细介绍新产品上线前需要准备哪些产品文档。 一、市场需求文档 市场需求文档&#xff08;Market Requirement Doc…

保姆级JAVA对接ChatGPT教程 使用 openai-gpt3-java

1. 前言 必须要有chatGTP 账号&#xff0c;如果需要测试账号可以关注公众号 疯狂的野猿 如果有chatGTP 账号就直接往下看。还需要一台外网服务器使用 nginx 代理来访问chatGTP 如果都没有&#xff0c;可以关注公众号联系作者。 还有笔者已经对接完成了&#xff0c;需要源码的关…

(电脑硬件)台式机主板音频端口功能详解

当你想给你的主机插上音响或者耳机时&#xff0c;你会发现主板上有6个接口&#xff0c;同样都是3.5mm接口&#xff0c;你知道该插哪个吗&#xff1f; 一般情况下&#xff0c;后置输入输出端口面板中&#xff0c;大多数的主板音频部分是彩色的。这一类颜色跟功能基本是固定的。当…

竟然支持在流程图、架构图中添加数学公式,安利一款纯免费的画图工具,真不错!

1. 简介 考虑到在绘图中需要添加数学表达式的场景&#xff0c;PDDON提供了LaTeX表达式编辑能力&#xff0c;可以在任何可以编辑的组件上启用LaTeX功能&#xff0c;使用LaTeX语法编写数学公式即可。 LaTeX表达式简介&#xff1a; LaTeX&#xff08;LATEX&#xff0c;音译“拉泰赫…

【偏门技巧】C语言编程实现对IPV4地址的合法性判断(使用正则表达式)

C语言编程实现对IPV4地址的合法性判断&#xff08;使用正则表达式&#xff09; 有了解过我的朋友&#xff0c;可能有点印象&#xff0c;我在N年前的博客中&#xff0c;就写了这个主题&#xff0c;当时确实是工作中遇到了这个问题。本想着等工作搞完之后&#xff0c;就把这个问题…

C++小知识点(for,nullptr)

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…

Ubuntu用户与用户组相关操作

目录 一、用户与用户组信息查看 二、用户管理 1、user1 2、user2 3、设置密码与删除用户 三、用户组管理 四、用户的切换 一、用户与用户组信息查看 查看用户&#xff0c;首先调出终端窗口&#xff0c;&#xff08;“sudo cat /etc/passwd”&#xff09;&#xff0c;输…

Day 50 小结

50.1 比较分析各种查找算法 顺序查找&#xff1a;时间复杂度&#xff1a;O(n)&#xff1b;可用于有序或无序数据&#xff1b;按顺序查找元素。 折半查找&#xff1a;时间复杂度&#xff1a;O(logn)&#xff1b;只能用于有序数据&#xff1b;从中间元素开始查找&#xff0c;每…

Linux 内核启动流程与入口函数分析

从启动引导程序 bootloader&#xff08;uboot&#xff09;跳转到 Linux 内核后&#xff0c;Linux 内核开始启动&#xff0c;今天我们分析一下 Linux 内核启动入口。 跳转过去初始化肯定是在汇编文件中&#xff0c;根据架构可以选择不同的平台&#xff0c;这里看一下链接汇编文…