412数据结构学习强化——常见数据结构定义和算法总结(五)

简介: 412数据结构学习强化——常见数据结构定义和算法总结

5.4.5.查找二叉树中两个结点的公共祖先结点

59da31125bff423a875a1b8ce85b8673.png

BiTNode *ans(BiTree ROOT, BiTNode *p, BiTNode *q) {
  Stack S, Sp, Sq;  //Sp和Sq分别用来保存p和q的祖先结点
  S.top = -1; //初始化队列
  BiTNode* t = ROOT, *pre = NULL;
  while (t || S.top >= 0) {
    if (t) {  //t结点非空
      S.data[++S.top] = t;  //t结点入队
      t = t->lchild;  //进入t的左子树
    }
    else {  //t结点为空
      t = S.data[S.top];  //查看栈顶元素
            //t的右子树存在,并且上一个访问的并不是其右子树
      if (t->rchild && t->rchild != pre) {  
        t = t->rchild;  //进入右子树
        S.data[++S.top] = t;  //入栈该结点
        t = t->rchild;  //进入左子树
      }
      else {  //右子树不存在,或者存在但是上一个访问的是右子树
        S.top--;  //出栈该结点,并访问
        if (t == p) { //当前结点为p,保存栈中内容,即其所有祖先结点
          for (int i = 0; i < S.top; i++) Sp.data[i] = S.data[i];
          Sp.top = S.top;
        }
        if (t == q) { //当前结点为q,保存栈中内容,即其所有祖先结点
          for (int i = 0; i < S.top; i++) Sq.data[i] = S.data[i];
          Sq.top = S.top;
        }
      }//if
    }//if
  }//while
    //自栈顶到栈顶分别遍历Sp和Sq找到最接近栈顶的相同祖先结点
  for (int i = Sp.top; i >= 0; i--) { 
    for (int j = Sq.top; i >= 0; j--) {
      if (Sp.data[i] == Sq.data[j]) return Sp.data[i];
    }
  }
  return NULL;  //无相同祖先顶点
}

5.4.6.求二叉树的宽度ccb1ae7ce764475ea764c119315612e4.png

typedef struct Queue{
    BiTNode *data[MAXSIZE];    //足够大的数组
    int front, rear;
}Queue;
int ans(BiTree T){
    if (!T) return 0;    //空树,返回0
    BiTNode *p = T;
    Queue Q;
    InitQueue(Q);    //初始化队列
    EnQueue(Q, p);    //将p入队
    //rear指向当前层的最后一个结点,count记录当前层的结点数,max记录最大结点数
    int last = Q.rear, count = 0, max = INT_MIN;    
    while (!IsEmpty(Q) {
        DeQueue(Q, p);
        count++;    //结点数+1
        if (p->lchild) EnQueue(Q, p->lchild);    //p的左子树存在,左子树入队
        if (p->rchild) EnQueue(Q, p->rchild);    //p的右孩子存在,右孩子入队
        if (last == Q.front) {    //当前结点是本层的最后一个节点
            last = Q.rear;    //last指向下一层的最后一个结点
            if (count > max) max = temp;    //更新最大结点数
            count = 0;    //结点数归零
        }
    }//while
    return max;
}
typedef struct Queue {  //足够大的非循环数组
  BiTNode *data[MAXSIZE]; //结点数组,保存每个结点
  int level[MAXSIZE]; //层数数组,记录每个结点的层数
  int front, rear;  //头尾指针
}Queue;
int ans(BiTree T) {
  BiTNode* p = T;
  Queue Q;
  Q.rear = Q.front = 0; //初始化队列
  if (T) {
    Q.data[Q.rear] = T; //根节点入队
    Q.level[Q.rear] = 1;
    Q.rear++;
    while (Q.front < Q.rear) {
      p = Q.data[Q.front];  //出队队首元素
      int level = Q.level[Q.front]; //保存当前结点的层数
      Q.front++;
      if (p->lchild) {  //左孩子入队
        Q.data[Q.rear] = p->lchild;
        Q.level[Q.rear] = level + 1;
        Q.rear++;
      }
      if (p->rchild) {  //右孩子入队
        Q.data[Q.rear] = p->rchild;
        Q.level[Q.rear] = level + 1;
        Q.rear++;
      }
    }//while
    int max = INT_MIN, i = 0, level = 1;
    while (i <= Q.rear) {
      int count = 0;  //记录当前层的结点数
      while (i <= Q.rear && level == Q.level[i]) {
        count++;
        i++;
      }
      if (count > max) max = count; //更新每层的最大结点数
      level = Q.level[i]; //更新层数,while循环结束时,i指向下一层的第一个结点
    }//while
    return max; //返回最大结点数
  }
  else return 0;  //空树,返回0
}

5.4.7.求二叉树的高度

int Get_Heigh(BiTree T) {
  int front = 0, rear = 0;  //前后指针
  BiTNode* p = T;
  BiTNode *data[MAXSIZE]; //足够大的队列,元素是二叉树结点
  data[rear++] = p; //根节点入队
  int last = rear, level = 0; //rear标记本层最后一个结点, level记录当前层数
  while (front < rear) {  //循环直到队空
    p = data[front++];  //出队队首结点
    if (p->lchild) data[Q.rear++] = p->lchild;  //左右孩子入队
    if (p->rchild) data[Q.rear++] = p->rchild;
    if (last == front) {  //当前结点为本层的最后一个结点
      last = rear;  //标记下层的最后一个结点
      level++;  //层数+1
    }
  }//while
  return level;
}
int Get_High(BiTree T){
    if (!T) return 0;    //空树返回0
    else {
        int hl = Get_High(T->lchild);    //递归求左右子树高度
        int hr = Get_High(T->rchild);
        int maxH = max(hl, hr) + 1;    //树高等于左右子树更高的那个+1
        return maxH;
    }
}

5.4.8.排序二叉树的判定

int pre = INT_MIN;  //标记上一个结点的值,初始值为INT类型的最小值
int JudgeBST(BiTree T) {
  if (!T) return 1; //空树,是排序二叉树
  else {
    int l = JudgeBST(T->lchild);  //判断左子树
        //当前值小于等于pre的值,或左子树不满足排序二叉树定义,返回0
    if (T->data <= pre|| l == 0) return 0;
    pre = T->data;  //更新pre为当前结点值
    int r = JudgeBST(T->rchild);  //判断右子树
    return r;
  }
}
int A[n]; //足够大的数组,保存每个节点的值
int count = 0;  //记录结点个数
void InOrder(BiTree T) {
  if (T) {
    InOrder(T->lchild); 
    A[count++] = T->data; //记录当前结点值,并且count+1
    InOrder(T->rchild);
  }
}
bool ans(BiTree T) {
  if (!T) return true;  //空树为排序二叉树
  else if (!T->lchild && !T->rchild) return true; //只有根节点,是排序二叉树
  else {
    InOrder(T); //中序遍历二叉树,并且记录每个结点的值
    for (int i = 0; i < count - 1; i++) {
      if (A[i] >= A[i + 1]) return false; //非排序二叉树
    }
    return true;  //排序二叉树
  }
}

5.4.9.平衡二叉树的判定

int Get_Height(BiTree T) {
  if (!T) return 0;
  else {
    int hl = Get_Height(T->lchild); //递归求左子树高度
    int hr = Get_Height(T->rchild); //递归求右子树高度
    int maxH = max(hl, hr) + 1; //树高为左右子树更高的那个 + 1
    return maxH;  
  }
}
bool JudgeBalance(BiTree T) {
  if (!T) return true;  //空树为平衡二叉树
  else {
    int hl = Get_Height(T->lchild); //左子树高度
    int hr = Get_Height(T->rchild); //右子树高度
    //当前结点的左右平衡因子小于等于1,递归判断其左右子树是否满足平衡二叉树
    if (abs(hl - hr) <= 1) {
            return JudgeBalance(T->lchild) && JudgeBalance(T->rchild);
        }
    //当前节点左右平衡因子大于1,则已不满足平衡二叉树,无需判断左右子树,返回false
    else return false;
  }
}

5.4.10.完全二叉树的判定

bool JudgeComplete(BiTree T) {
  BiTNode* data[MAXSIZE]; //足够大的队列
  int front = 0, rear = 0;  //头尾指针
  BiTNode* p = T; 
  data[rear++] = T; //根节点入队
  while (front < rear) {  //循环直到队空
    p = data[front++];  //出队队首元素
    if (p) {  //p结点存在,入队左右孩子
      data[rear++] = p->lchild;
      data[rear++] = p->rchild;
    }
    else {  //p结点不存在,出队剩余元素
      while (front < rear) {
        p = data[front++];
        if p == NULL return false;  //当前元素为空,则为非完全二叉树
      }
    }
  }
  return true;
}

5.4.11.真题6f2f5d0118df435db4b92a0872d5d5ce.png

int WPL = 0;
void InOrder(BiTree T, int deep){
    if (T) {
        if (!T->left && !T->right) {    //叶子结点
            WPL = WPL + T.weight * deep;    //更新WPL
        }
        if (T->left) InOrder(T->left, deep + 1);
        if (T->right) InOrder(T->right, deep + 1);
    }
}
int ans(BiTree T){
    InOrder(T, 0);
    return WPL;
}
int Get_WPL(BiTree root) {
  BiTNode* data[MAXSIZE]; //足够大的非循环数组
  BiTNode* p = root;
  int f = 0, r = 0, level = 0, WPL = 0, last = 0; 
  data[r++] = p;  //根节点入队
  last = r; //last标记本层的最后一个元素
  while (f < r) {
    p = data[f++];  //队首元素出队
        //该结点为叶子结点,计算WPL
    if (!p->lchild && !p->rchild) WPL = WPL + level * p->weight;
    if (p->lchild) data[r++] = p->left; //左右孩子入队
    if (p->rchild) data[r++] = p->right;
    if (last == f) {  //该结点为本层的最后一个结点
      last = r; //更新last和level
      level++;
    }
  }
    return WPL;
}
f184da9060ed4f348f5a5207d442c7f6.png
void InOrder(BiTree T, int deep){
    if (T) {
        if (deep > 1 && (T->lchild || T->rchild)) cout << '(';    //分支节点打印左括号
        if (T->lchild) InOrder(T->lchild, deep + 1);
        cout << T->data;
        if (T->rchild) InOrder(T->rchild, deep + 1);
        if (deep > 1 && (T->lchild || T->rchild)) cout << ')';    //分支节点打印右括号
    }
}
void ans(BiTree T){
    InOrder(T, 1);
}

6.图

6.1.图的数据结构定义

6.1.1.邻接矩阵

#define MAXVEX 100
typedef struct Graph {
    int data[MAXVEX];    //一维数组,存放顶点数据
    int edge[MAXVEX][MAXVEX];    //二维数组,存放边数据(权值)
    int vexNum, edgeNum;    //顶点总数和边总数
}Graph;

6.1.2.邻接表

#define MAXVEX 100
typedef struct edgeNode {    //边
    struct edgeNode *next;    //指向下一条邻接边的指针
    int weight;    //该邻接边权值
    int adjVex;    //该邻接边指向的顶点编号
}edgeNode;
typedef struct vexNode {    //顶点
    edgeNode *firstEdge;    ///指向该顶点的第一条邻接边
    int vexData;    //该顶点数据
}vexNode;
typedef struct Graph {    //图
    int vexNum, edgeNum;    //顶点数,边数
    vexNode vex[MAXVEX];    //vexNode类型的一维数组vex
}Graph;

6.2.图的遍历

6.2.1.深度优先遍历

#define MAXVEX 100
bool visited[MAXVEX];    //visited数组记录该顶点是否被访问过
void DFSTraverse (Graph G) {
    for (int i = 0; i < G.vexNum; i++) {
        visited[i] = false;    //初始化visited数组
    }
    for (int i = 0; i < G.vexNum; i++) {
        if (!visited[i]) DFS (G, i);    //当前顶点未被访问过,则访问
    }
}
void DFS (Graph G, int v) {
    visit (v);    //访问顶点v(具体操作)
    visited[v] = true;    //更新visited数组
    for (int w = FirstNeighbor (G, v); w >= 0; w = NextNeighbor (G, v, w)){
        if (!visited[w]) DFS(G, w);    //递归调用DFS
    }
}

6.2.2.广度优先遍历

#define MAXVEX 100
Queue Q;
bool visited[MAXVEX];
void BFSTraverse (Graph G) {
    for (int i = 0; i < G.vexNum; i++) {    //初始化visited数组
        visited[i] = false;    
    }
    InitQueue Q;    //初始化队列Q
    for (int i = 0; i < G.vexNum; i++) {    //遍历图
        if (!visited[i]) BFS(G, i);
    }
}
void BFS (Graph G, int v) {
    visit(v);    //访问该顶点(具体操作)
    visited[v] = true;    //更新visited数组
    EnQueue(Q, v);    //将v结点入队
    int w;
    while(!IsEmpty(Q)) {
        DeQueue(Q, v);    //队首元素出队
        for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) {
            if (!visited[w]) {    //顶点未被访问过
                visit(w);
                visited[w] = true;
                EnQueue(Q, w);
            }
        }//for
    }//while
}

6.3.单源最短路径

#define MAXVEX 100
bool visited[MAXVEX];
int dis[MAXVEX];
Queue Q;
void Min_Dis (Graph G, int v) {
    for (int i = 0; i < G.vexNum; i++) {    //初始化visited数组和dis数组
        visited[i] = false;
        dis[i] = INT_MAX;
    }
    visited[v] = true;
    dis[v] = 0;
    InitQueue(Q);
    EnQueue(Q, v);
    int w;
    while (!IsEmpty(Q)) {
        DeQueue(Q, v);
        for (w = FisrtNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w) {
            if (!visited[w]) {
                visited[w] = true;
                dis[w] = dis[v] + 1;
            }
        }//for
    }//while
}

6.4.真题

fa4a011572674952bb92acaee9c519c5.png

int IsExistEL(MGraph G){
    int count = 0;    //记录该图中度为奇数的顶点个数
    int i, j;
    for (i = 0; i < G.numVertices; i++){    //行遍历邻接矩阵
        int degree = 0;
        for (j = 0; j < G.numVertices; j++){    //列遍历当前行
            if (Edge[i][j] > 0) degree++;    //当前数组元素不为0,则度+1
        }
        if (degree % 2) count++;    //当前顶点的度为奇数,count++
    }
    if (count == 0 || count == 2) return 1;    //奇数顶点个数为0或者2,有EL路径
    else return 0;    //奇数顶点个数不为0或者2,没有EL路径
}

7.快速排序

void QSort(int A[], L, R) {    //快速排序
    if (L >= R) return;    //当前数组长度 <= 1,返回
    随机选择数组中一元素和A[L]互换    //快排优化,使得基准元素的选取随机
    int key = A[L], i = L, j = R;
    while (i < j) {
        while (i < j && key < A[j]) j--;
        while (i < j && A[i] <= key) i++;
        if (i < j) swap (A[i], A[j]);    //交换A[i]和A[j]
    }
    swap (A[i], A[L]);
    Qsort (A, L, i - 1);    //递归处理左区间
    Qsort (A, i + 1, R);    //递归处理右区间
}

8.折半查找

int Binary_Search (int A, L, R, key) {
    int mid;
    while (L < R) {    //L >= R时,范围错误
        mid = (L + R) / 2;    //选择中间数,向下取整
        if (key <= A[mid]) R = mid;    //更新范围
        else L = mid + 1;
    }
    if (A[mid] == key) return mid;    //查找成功,返回数组下标
    else return -1;    //查找失败,返回-1
}


相关文章
|
27天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
数据结构与算法系列学习之串的定义和基本操作、串的储存结构、基本操作的实现、朴素模式匹配算法、KMP算法等代码举例及图解说明;【含常见的报错问题及其对应的解决方法】你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
|
23天前
|
机器学习/深度学习 人工智能 自然语言处理
【EMNLP2024】基于多轮课程学习的大语言模型蒸馏算法 TAPIR
阿里云人工智能平台 PAI 与复旦大学王鹏教授团队合作,在自然语言处理顶级会议 EMNLP 2024 上发表论文《Distilling Instruction-following Abilities of Large Language Models with Task-aware Curriculum Planning》。
|
27天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习(8)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
27天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
27天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
27天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
IKU达人之数据结构与算法系列学习×单双链表精题详解、数据结构、C++、排序算法、java 、动态规划 你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
24天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
114 9
|
15天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
22 1
|
2天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
19 5
|
17天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
下一篇
无影云桌面