第4章树与二叉树

数据结构第4章树的定义总结 二叉搜索树的性质 1)非空左子树的所有键值小于其根节点的键值; 2) 非空右子树的键值大于其根节点的键值; 3) 左右子树都是二叉搜索树 若一棵搜索树(查找树)是一个有n个结点的完全二叉树,则该树的最小值一定在叶结点上,该树的最大值不一定在叶结点上 分析:搜索树最大值可以有左儿子,没有右儿子; 二叉搜索树不是完全二叉树 任何二叉搜索在每一层都是有序的(从小到大) ... 阅读详情

属于二叉树

跟链表的不同:每个节点可以指向多个节点

所以直接改变next[n]就好

链表是树形结构特例

树的深度(高度): 层数 =5 [1 4 5 7 8]

节点深度:从根节点开始,4的深度:[1 4] =1

节点高度:从叶子节点开始,4的高度:[8 7 5 4]=3

8号节点高度为0

1号节点深度为0

节点的度:子节点数量:1号节点度为3

叶子节点度为0

度分为入度和出度:

​ 入度:几个节点指向我,1号节点入度为0 :父节点

​ 出度:我指向了几个节点 ,8号节点出度为0 :子节点

节点数量=边数+1

n个节点=n-1条边

树的节点代表几个,边代表关系

根节点代表全集

广度优先遍历和深度优先遍历

广度遍历是层序遍历,一层一层

深度遍历是,遍历子子子,直到没有子,回溯,再找有没有没有遍历的子节点,回溯-遍历

看两个节点是不是父子关系:看子节点在不在父节点范围内

广度优先:

1 入 2 3 入 1 出

4 入 2 出

5 6 7入 3 出

8 9 入

深度优先:

1 2 4 入 没了 弹出栈顶 4 2

1 有 3 5 入 弹5

6 入 8 入 弹8

9入 9 弹

6弹

7 入 7 弹

3 弹

1 弹

:1 2 4 4 2 3 5 5 6 8 8 9 9 6 7 7 3 1 -》范围内表示是子树

二叉树

二叉树每个节点度最多为2

二叉树度0为的节点比度为2的节点多一个

点数=边数+1

n0+n1+n2=n1+2n2+1

n0=n2+1

度为0的节点比度为1的节点多一个

完全二叉树:除了最后一层以外,上面的都是慢的

​ 左孩子:2*i

​ 右孩子:2*i+1

满二叉树:没有度为0的树

完美二叉树:每一层都是满的

练习递归技巧的最佳选择:

数学归纳法-》结构归纳法

左孩子有兄弟表示法节省空间《–多叉树都可以转为二叉树

左边表示孩子,右边表示兄弟

#include <cstdlib>
#include <ctime>
#include <cstdio>

//
// Created by cry on 2024/3/15.
//
typedef struct Node{
    int key;
    struct Node *lchild,*rchild;
}Node;
//初始化二叉树节点
Node *acm_1_5_shu_guangdubianli_getNewNode(int key){
    Node *p=(Node *)malloc(sizeof(Node));
    p->key=key;
    p->lchild=p->rchild=NULL;
    return p;
}
//了无牵挂式析构法
void acm_1_5_shu_guangdubianli_clear(Node *root){
    if (root ==NULL) return;
    acm_1_5_shu_guangdubianli_clear(root->lchild);
    acm_1_5_shu_guangdubianli_clear(root->rchild);
    free(root);
    return ;
}
Node *acm_1_5_shu_guangdubianli_insert(Node *root,int key){
    if(root ==NULL) return acm_1_5_shu_guangdubianli_getNewNode(key);
    if(rand() %2) root->lchild= acm_1_5_shu_guangdubianli_insert(root->lchild,key);
    else root->rchild= acm_1_5_shu_guangdubianli_insert(root->rchild,key);
    return root;
}

#define MAX_NODE 10
int head,tail;
Node *queue[MAX_NODE+5];
//广度优先
void dfs(Node *root){
    head=tail=0;
    queue[tail++]=root;
    while(head<tail){
        Node *node=queue[head];
        printf("\n node:%d\n",node->key);

        if(node->lchild) {
            queue[tail++] = node->lchild;
            printf("\t%d->%d(left)\n",node->key,node->lchild->key);
        }
        if(node->rchild) { queue[tail++] = node->rchild;
            printf("\t%d->%d(right)\n",node->key,node->rchild->key);}
        head++;
    }
    return ;
}
//深度优先遍历
int tot=0;
void bfs(Node *root){
    if(root == NULL) return;
    tot+=1;
    int start,end;
    start=tot;
    if(root->lchild) bfs(root->lchild);
    if(root->rchild) bfs(root->rchild);

    tot+=1;
    end=tot;
    printf("%d:[%d,%d]\n",root->key,start,end);

}
void acm_1_5_shu_guangdubianli_test(){
    srand(time(0));
    Node *root=NULL;
    for(int i=0;i<MAX_NODE;i++){
        root= acm_1_5_shu_guangdubianli_insert(root,rand()%100);
    }
    bfs(root);
    dfs(root);
//    return 0;
}

左右表示左子树

前序遍历:根左右 :1 2 4 5 3 6

中序遍历:左根右 :4 2 5 1 3 6

后序遍历:左右根:4 5 2 6 3 1

用于序列化

线索化:

右边空指针:前驱

左边空指针:后继

二叉树的遍历展现的像链表

//
// Created by cry on 2024/3/15.
//
//acm_1_5_shu_bainliheXiansuohua_
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
typedef struct Node{
    int key,ltag,rtag; //ltag表示左边边标记,ltag=1表示左边是线索  0:正常边
    struct Node *lchild,*rchild;
}Node;
Node *acm_1_5_shu_bainliheXiansuohua_getNewNode(int key){
    Node *p=(Node *) malloc(sizeof(Node));
    p->key=key;
    p->lchild=p->rchild=NULL;
    p->ltag=p->rtag=0;
    return p;
}
Node *acm_1_5_shu_bainliheXiansuohua_insert(Node *root,int key){
    if(root ==NULL) return acm_1_5_shu_bainliheXiansuohua_getNewNode(key);
    if(rand() %2) root->lchild= acm_1_5_shu_bainliheXiansuohua_insert(root->lchild,key);
    else root->rchild= acm_1_5_shu_bainliheXiansuohua_insert(root->rchild,key);
    return root;
}
void acm_1_5_shu_bainliheXiansuohua_clear(Node *root){
    if(root==NULL) return;
    if(root->ltag==0)acm_1_5_shu_bainliheXiansuohua_clear(root->lchild);
    if(root->rtag==0)acm_1_5_shu_bainliheXiansuohua_clear(root->rchild);
    acm_1_5_shu_bainliheXiansuohua_clear(root);
    return ;
}
//前序遍历
void acm_1_5_shu_bainliheXiansuohua_pre_order(Node *root){

    if(root==NULL) return;
    printf("%d ",root->key);
    if(root->ltag==0)acm_1_5_shu_bainliheXiansuohua_pre_order(root->lchild);
    if(root->rtag==0)acm_1_5_shu_bainliheXiansuohua_pre_order(root->rchild);
    return;
}
//中序遍历
void acm_1_5_shu_bainliheXiansuohua_in_order(Node *root){
    if(root==NULL) return;
    if(root->ltag==0)acm_1_5_shu_bainliheXiansuohua_in_order(root->lchild);
    printf("%d ",root->key);
    if(root->rtag==0)acm_1_5_shu_bainliheXiansuohua_in_order(root->rchild);
}
Node *pre_node=NULL,*inorder_root=NULL;
void __acm_1_5_shu_bainliheXiansuohuabuild_in_order_thread(Node *root){
    if(root==NULL) return;
    if(root->ltag==0)__acm_1_5_shu_bainliheXiansuohuabuild_in_order_thread(root->lchild);
    if(inorder_root==NULL){inorder_root=root;}
    if(root->lchild==NULL) {
        root->lchild = pre_node;
        root->ltag = 1;
    }
    if(pre_node && pre_node->rchild==NULL){
        pre_node->rchild=root;
        pre_node->rtag=1;
    }
    pre_node=root;

    if(root->rtag==0)__acm_1_5_shu_bainliheXiansuohuabuild_in_order_thread(root->rchild);
}
void acm_1_5_shu_bainliheXiansuohuabuild_in_order_thread(Node *root){
    __acm_1_5_shu_bainliheXiansuohuabuild_in_order_thread(root);
    pre_node->rchild=NULL;
    pre_node->rtag=1;
    return ;
}
//后序遍历
void acm_1_5_shu_bainliheXiansuohua_post_order(Node *root){
    if(root==NULL) return;
    if(root->ltag==0)acm_1_5_shu_bainliheXiansuohua_post_order(root->lchild);
    if(root->rtag==0)acm_1_5_shu_bainliheXiansuohua_post_order(root->rchild);
    printf("%d ",root->key);
}
Node *acm_1_5_shu_bainliheXiansuohua_getNext(Node *root){
    if(root->rtag==1) return root->rchild;
    root=root->rchild;
    while(root->ltag==0 && root->lchild){
        root=root->lchild;
    }
    return root; //右子树最左边-后继
}
void acm_1_5_shu_bainliheXiansuohua_test(){
    srand(time(0));
    Node *root=NULL;
#define MAX_NODE 10
    for (int i = 0; i < MAX_NODE; i++) {
        root=acm_1_5_shu_bainliheXiansuohua_insert(root,rand()%100);
    }
    pre_node=NULL,inorder_root=NULL;
    acm_1_5_shu_bainliheXiansuohuabuild_in_order_thread(root);
    printf("\n");
    acm_1_5_shu_bainliheXiansuohua_pre_order(root);
    printf("\n");
    acm_1_5_shu_bainliheXiansuohua_in_order(root);
    printf("\n");
    acm_1_5_shu_bainliheXiansuohua_post_order(root);
    printf("\n");

    Node *node=inorder_root;
    while(node) {
        printf("%d ",node->key);
        node = acm_1_5_shu_bainliheXiansuohua_getNext(node);
    }

    acm_1_5_shu_bainliheXiansuohua_clear(root);
    return;
}

广义表表示法

将二叉树表示为字符串

空树:()

一个节点:A / A()

两个节点:A(B,) / A(B)

只有右子树:A(,B)

只有左子树,可没有逗号:A(B)

三个结点:A(B,C)

A(B(,D),C(E))

//
// Created by cry on 2024/3/15.
//
//acm_1_5_shu_serialize_deserialize_
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define KEY(n) (n?n->key:-1) //-1表示没有值
//二叉树转广义表
typedef struct Node{
    int key;
    struct Node *lchild,*rchild;
}Node;
Node *acm_1_5_shu_serialize_deserialize_getNewNode(int key){
    Node *p=(Node *) malloc(sizeof(Node));
    p->key=key;
    p->lchild=p->rchild=NULL;
    return p;
}
void acm_1_5_shu_serialize_deserialize_clear(Node *root){
    if(root==NULL)return ;
    acm_1_5_shu_serialize_deserialize_clear(root->lchild);
    acm_1_5_shu_serialize_deserialize_clear(root->rchild);
    acm_1_5_shu_serialize_deserialize_clear(root);
}
Node *acm_1_5_shu_serialize_deserialize_insert(Node *root,int key){
    if(root==NULL){return acm_1_5_shu_serialize_deserialize_getNewNode(key);}
    if(rand()%2)root->lchild= acm_1_5_shu_serialize_deserialize_insert(root->lchild,key);
    else root->rchild= acm_1_5_shu_serialize_deserialize_insert(root->rchild,key);
    return root;
}
Node *acm_1_5_shu_serialize_deserializ_getRandomBinaryTree(int n){
    Node *root=NULL;
    for (int i = 0; i < n; i++) {
        root=acm_1_5_shu_serialize_deserialize_insert(root,rand()%100);
    }
    return root;
}


//开始变成广义表-序列化
char buff[1000];
int len=0;
void __acm_1_5_shu_serialize_deserialize_serialize(Node *root){
    if (root==NULL) return;
    //根(左,右)
    len+=snprintf(buff+len,100,"%d",root->key);

    if(root->lchild==NULL && root->rchild==NULL) return;
    len+= snprintf(buff+len,100,"(");
    __acm_1_5_shu_serialize_deserialize_serialize(root->lchild);
    if(root->rchild){
        len+=  snprintf(buff+len,100,",");
        __acm_1_5_shu_serialize_deserialize_serialize(root->rchild);
    }
    len+=  snprintf(buff+len,100,")");
    return ;
}
void acm_1_5_shu_serialize_deserialize_serialize(Node *root){
    memset(buff,0,sizeof(buff));
    len=0;
    __acm_1_5_shu_serialize_deserialize_serialize(root);
    return ;
}
void acm_1_5_shu_serialize_deserializ_print(Node *root){
    printf("%d(%d,%d)\n",KEY(root),KEY(root->lchild),KEY(root->rchild));
    return;
}
void acm_1_5_shu_serialize_deserializ_output(Node *root){
    if(root==NULL) return;
    acm_1_5_shu_serialize_deserializ_print(root);
    acm_1_5_shu_serialize_deserializ_output(root->lchild);
    acm_1_5_shu_serialize_deserializ_output(root->rchild);
    return;
}
void acm_1_5_shu_serialize_deserialize_test(){
    srand(time(0));
#define MAX_NODE 10
    Node *root= acm_1_5_shu_serialize_deserializ_getRandomBinaryTree(MAX_NODE);
    //拥有了10个结点的二叉树

    //二叉树变成广义表-序列化

    acm_1_5_shu_serialize_deserialize_serialize(root);
    printf("Buff[] : %s\n",buff);

    //对比,输出二叉树前序遍历和中序遍历
    acm_1_5_shu_serialize_deserializ_output(root);

}

广义表转二叉树

A -> 直接节点A

A(,B) ->

  1. 遇到关键字就生成新的节点
  2. 遇到左括号就把新生成的节点压入栈
  3. 遇到 逗号 , **标记(flag)**当前处理右子树了
  4. 遇到右括号就将栈顶元素出栈
  5. 每次生成一个新的节点的时候根据标记设置栈顶元素的左右子树
//
// Created by cry on 2024/3/15.
//
//acm_1_5_shu_serialize_deserialize_
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define KEY(n) (n?n->key:-1) //-1表示没有值
#define MAX_NODE 10
//二叉树转广义表
typedef struct Node{
    int key;
    struct Node *lchild,*rchild;
}Node;
Node *acm_1_5_shu_serialize_deserialize_getNewNode(int key){
    Node *p=(Node *) malloc(sizeof(Node));
    p->key=key;
    p->lchild=p->rchild=NULL;
    return p;
}
void acm_1_5_shu_serialize_deserialize_clear(Node *root){
    if(root==NULL)return ;
    acm_1_5_shu_serialize_deserialize_clear(root->lchild);
    acm_1_5_shu_serialize_deserialize_clear(root->rchild);
    acm_1_5_shu_serialize_deserialize_clear(root);
}
Node *acm_1_5_shu_serialize_deserialize_insert(Node *root,int key){
    if(root==NULL){return acm_1_5_shu_serialize_deserialize_getNewNode(key);}
    if(rand()%2)root->lchild= acm_1_5_shu_serialize_deserialize_insert(root->lchild,key);
    else root->rchild= acm_1_5_shu_serialize_deserialize_insert(root->rchild,key);
    return root;
}
Node *acm_1_5_shu_serialize_deserializ_getRandomBinaryTree(int n){
    Node *root=NULL;
    for (int i = 0; i < n; i++) {
        root=acm_1_5_shu_serialize_deserialize_insert(root,rand()%100);
    }
    return root;
}


//TODO 开始变成广义表-序列化
char buff[1000];
int len=0;
void __acm_1_5_shu_serialize_deserialize_serialize(Node *root){
    if (root==NULL) return;
    //根(左,右)
    len+=snprintf(buff+len,100,"%d",root->key);

    if(root->lchild==NULL && root->rchild==NULL) return;
    len+= snprintf(buff+len,100,"(");
    __acm_1_5_shu_serialize_deserialize_serialize(root->lchild);
    if(root->rchild){
        len+=  snprintf(buff+len,100,",");
        __acm_1_5_shu_serialize_deserialize_serialize(root->rchild);
    }
    len+=  snprintf(buff+len,100,")");
    return ;
}
void acm_1_5_shu_serialize_deserialize_serialize(Node *root){
    memset(buff,0,sizeof(buff));
    len=0;
    __acm_1_5_shu_serialize_deserialize_serialize(root);
    return ;
}

//广义表转二叉树
Node *acm_1_5_shu_serialize_deserialize_deserialize(char *buff,int n){
//手撸栈麻烦,用数组
    Node **s=(Node **) malloc(sizeof(Node *)*MAX_NODE );
    int top=-1,flag=0,scode=0; //状态码scode,用状态机
    Node *p=NULL,*root=NULL;
    for(int i=0;buff[i];i++){
        switch(scode){ //每一种状态码下应该干什么
            case 0:{
                if(buff[i]>='0' && buff[i] <='9'){
                    scode=1;
                }
                else if(buff[i]=='('){
                    scode=2;
                }
                else if(buff[i]==','){
                    scode=3;
                }else scode=4;
                i-=1;
            }
                break;
            case 1:{
                //新建一个节点
                int key=0;
                while(buff[i] <='9' && buff[i]>='0'){
                    key=key*10+(buff[i]-'0');//字符串转为数字
                    i+=1;
                }
                p=acm_1_5_shu_serialize_deserialize_getNewNode(key);
                //设置为栈顶元素的左子树或右子树
                if(top >=0){
                    if(flag==0){
                        s[top]->lchild=p;
                    }
                    else if(flag==1){
                        s[top]->rchild=p;
                    }
                }
                //收尾工作
                i-=1;
                scode=0;
            }
                break;
            case 2:{
                //压栈
                s[++top]=p;
                flag=0;
                scode=0;
            }
                break;
            case 3:{
                flag=1;
                scode=0;
            }
                break;
            case 4:{
                root=s[top];
                top-=1; //弹栈
                scode=0;
            }
                break;
        }
    }
    return root;
}
void acm_1_5_shu_serialize_deserializ_print(Node *root){
    printf("%d(%d,%d)\n",KEY(root),KEY(root->lchild),KEY(root->rchild));
    return;
}
void acm_1_5_shu_serialize_deserializ_output(Node *root){
    if(root==NULL) return;
    acm_1_5_shu_serialize_deserializ_print(root);
    acm_1_5_shu_serialize_deserializ_output(root->lchild);
    acm_1_5_shu_serialize_deserializ_output(root->rchild);
    return;
}
void acm_1_5_shu_serialize_deserialize_test(){
    srand(time(0));

    Node *root= acm_1_5_shu_serialize_deserializ_getRandomBinaryTree(MAX_NODE);
    //拥有了10个结点的二叉树

    //二叉树变成广义表-序列化

    acm_1_5_shu_serialize_deserialize_serialize(root);
    printf("Buff[] : %s\n",buff);

    //对比,输出二叉树前序遍历和中序遍历
    acm_1_5_shu_serialize_deserializ_output(root);
    printf("\n");
    Node *new_root=acm_1_5_shu_serialize_deserialize_deserialize(buff,len);
    acm_1_5_shu_serialize_deserializ_output(new_root);
    return ;
}

哈夫曼编码

编码方式导致网速明显感到差别

zoom和腾讯会议早期对比

明明只传26个字母5字节 非要用ascii8字节,慢3秒

变长编码:每个字母长度不一样

定长编码:每个字母长度一样

例如:传输 a b c d四种字符,共100个字符

定长:只用两个比特位:2*100=200/100=2s

变长:a:1 b:011 c:010 d:00 出现概率越高字符越小:50*1+20*3+10*3+20*2=180

所以怎么衡量两套编码?

平均编码长度!

0.5*1+0.2*3+0.1*3+0.2*2=1.8

哈夫曼编码–最优的变长编码

6666666

证明

第h层有2^h个节点总数

第h层覆盖了2^(h-Li)个节点

不超过h层节点数量上限

和信息熵有关

//
// Created by cry on 2024/3/16.
//
//acm_1_5_shu_hafuman_


#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <cassert>
#include <cstring>
#define MAX_CHAR_NUM 128

using namespace std;
typedef struct Node{
    char ch;
    int freq;
    struct Node *lchild,*rchild;
}Node;
Node *acm_1_5_shu_hafuman_getNewNode(int freq,char ch){
    Node *p=(Node *) malloc(sizeof(Node));
    p->lchild=p->rchild=NULL;
    p->ch=ch;
    p->freq=freq;
    return p;
}
void acm_1_5_shu_hafuman_clear(Node *root){
    if(root==NULL) return;
    acm_1_5_shu_hafuman_clear(root->lchild);
    acm_1_5_shu_hafuman_clear(root->rchild);
    acm_1_5_shu_hafuman_clear(root);
}
void acm_1_5_shu_hafuman_swap_node(Node **node_arr,int i,int j){
    Node *temp=node_arr[i];
    node_arr[i]=node_arr[j];
    node_arr[j]=temp;
    return ;
}
int acm_1_5_shu_hafuman_find_min_node(Node **node_arr,int n){
    int ind=0;
    for(int j=0;j<=n;j++){
        if(node_arr[ind]->freq > node_arr[j]->freq) ind=j;
    }
    return ind;
}
Node *acm_1_5_shu_hafuman_buildHaffmanTree(Node **node_arr,int n){
    //TODO find_two_min_node 找到两个最小值节点
    for(int i=1;i<n;i++){
        //进行n-1次合并
        //找两个最小值的节点,结束后,最小值在最后
//        Node *temp=node_arr[0]; //找最小值
        int ind1=acm_1_5_shu_hafuman_find_min_node(node_arr,n-i);

//节点交换
        acm_1_5_shu_hafuman_swap_node(node_arr,ind1,n-i);
        int ind2=acm_1_5_shu_hafuman_find_min_node(node_arr,n-i-1);
        acm_1_5_shu_hafuman_swap_node(node_arr,ind2,n-i-1);
        //TODO merge_to_node合并成一个节点并回到数组最后一位
        int freq=node_arr[n-i]->freq+node_arr[n-i-1]->freq;
        Node *node=acm_1_5_shu_hafuman_getNewNode(freq,0);
        node->lchild=node_arr[n-i-1]; //左子树为次小值节点
        node->rchild=node_arr[n-i]; //右子树为最小值节点
        node_arr[n-i-1]=node;
    }
    return node_arr[0]; //结束后根节点在第一位
}
void acm_1_5_shu_hafuman_output(Node **node_arr,int n){
    for(int i=0;i<n;i++){
        cout << node_arr[i]->ch << " " << node_arr[i]->freq << endl;
//        printf("%c %d\n",node_arr[i]->ch,node_arr[i]->freq);
    }
    return ;
}
char *char_code[128]={0}; //数组

void acm_1_5_shu_hafuman_extractHaffmanCode(Node *root,char buff[],int k){ //k为路径长度
    buff[k]=0;
    //当前节点是不是叶子节点,如果是,直接返回
    if(root->lchild==NULL && root->rchild==NULL){
        char_code[root->ch]=strdup(buff);
        printf("%c:%s\n",root->ch,buff);
        return;
    }
    buff[k]='0';
    acm_1_5_shu_hafuman_extractHaffmanCode(root->lchild,buff,k+1);
    buff[k]='1';
    acm_1_5_shu_hafuman_extractHaffmanCode(root->rchild,buff,k+1);
    return;
}
void acm_1_5_shu_hafuman_test(){
    string filename = "input2.txt";
    ifstream file(filename);
    string line;
    assert( file.is_open() );   // 确定文件打开了;
    getline(file, line);
    int n,freq;
    char s;
    n= stoi(line);
//    scanf("%d",&n);
    Node **node_arr=(Node **) malloc(sizeof(Node*)*n); //二维数组
    printf("开始\n");
    for(int i=0;i<n;i++){
        getline(file, line); // 读取每行数据
        stringstream ss(line);
        ss >> s >> freq;  // 从文件中读取字符和频率
//        cout << s << " " << freq << endl;
//        scanf("%s%d",s,&freq);
        node_arr[i]= acm_1_5_shu_hafuman_getNewNode(freq,s);
    }
    acm_1_5_shu_hafuman_output(node_arr,n);
    printf("\n");
    Node *root=acm_1_5_shu_hafuman_buildHaffmanTree(node_arr,n);
//提取相关编码信息
    char buff[1000];
    acm_1_5_shu_hafuman_extractHaffmanCode(root,buff,0);
    for(int i=0;i<MAX_CHAR_NUM;i++){
        if(char_code[i]==NULL) continue;
        //char_code[i]不为空,输出字符
        printf("%c:%s\n",i,char_code[i]); //按照ABCD顺序输出(字典序)
    }
    acm_1_5_shu_hafuman_clear(root);
}

习题环节

二叉树的前序遍历 : 跟左右

N叉树:根 1 2 3棵树

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/
// N叉树前序遍历
class Solution {
public:
    vector<int> preorder(Node* root) {
        if(root ==NULL) return vector<int>();
        //不为空
        vector<int> ans; //遍历结果
        ans.push_back(root->val);
        for(auto x:root->children) //一次扫描root的子节点
        {
            //x每个子树的前序遍历结果 给temp
            vector<int> temp=preorder(x); //先每个子树
            for(auto y:temp){
                //然后temp遍历
                ans.push_back(y);
            }
        }
        return ans;
    }
};
效率低

没有什么是一层封装解决不了的,如果有,就两层

class Solution {
public:
//传入引用是为了减少数据拷贝次数
    void __preorder(Node *root,vector<int> &ans){
        if(root==NULL) return;
        ans.push_back(root->val);
        for(auto x:root->children){
            __preorder(x,ans);
        }
        return ;
    }
    vector<int> preorder(Node* root) {
        vector<int> ans; //root前序遍历结果
        __preorder(root,ans);
        return ans;
    }
};

105leet:前中序回复二叉树

左子树的前中序 合成大的左子树

右子树的前中序 合成大的右子树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        //边界条件为size==0
        int n=preorder.size();
        if(n==0) return NULL;
        int pos=0; //中序遍历中根节点的位置
        while(inorder[pos]!=preorder[0]){
            pos+=1;
        }
        //找到了根节点位置
        //前序1-pos为左子树
        //中序0到pos-1为左子树
        TreeNode *root=new TreeNode(preorder[0]);
        vector<int> preArr,inArr; //存储左右子树的前中序遍历结果
        for(int i=1;i<=pos;i++){
            preArr.push_back(preorder[i]); //左子树前序遍历结果
        }
        for(int i=0;i<pos;i++){
            inArr.push_back(inorder[i]); //左子树中序遍历结果
        }
        root->left=buildTree(preArr,inArr); //然后继续左子树往下分
        preArr.clear();
        inArr.clear();
        for(int i=pos+1;i<n;i++){
            preArr.push_back(preorder[i]); //右边子树前序遍历结果
        }
        for(int i=pos+1;i<n;i++){
            inArr.push_back(inorder[i]); //左子树中序遍历结果
        }
        //回复右子树
        root->right=buildTree(preArr,inArr); //然后继续左子树往下分
        return root; 
    }
    
};
class Solution(object):
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if not preorder or not inorder:
            return None

        root_val = preorder[0]
        root_index = inorder.index(root_val) #在中序遍历中找到根节点
		# while(inorder[pos]!=preorder[0]):pos+=1;
        root = TreeNode(root_val)
        # 左子树是1:pos 0:pos
        root.left = self.buildTree(preorder[1:root_index+1], inorder[:root_index])
        # 右子树是:pos+1:n  pos+1:n
        root.right = self.buildTree(preorder[root_index+1:], inorder[root_index+1:])

        return root

leetcode102:二叉树层序遍历

用队列

广搜 或者 深搜都可以

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []
        q = [root]
        ans = []
        while q:
            t = []
            for _ in range(len(q)):
                node = q.pop(0)
                t.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            ans.append(t) #每次压入一层
        return ans
        

队列:用广搜完成层序遍历

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root==NULL) return vector<vector<int>>();
        TreeNode *node;
        queue<TreeNode *>  q; //队列,类型为TreeNode
        vector<vector<int>> ans;
        q.push(root); 
        while(!q.empty()){
            int cnt=q.size();
            vector<int> temp;
            for(int i=0;i<cnt;i++){
                node=q.front();
                temp.push_back(node->val);
                if(node->left) q.push(node->left);
                if(node->right) q.push(node->right);
                q.pop();
            }
            ans.push_back(temp);
        }
    return ans;
        
    }
};

栈:用深搜完成层序遍历

只需要在深搜过程中记录层数就行

class Solution{
    public:
    void dfs(TreeNode *node,int k,vector<vector<int>> &ans){
        if(node ==NULL) return;
        if(k==ans.size()) ans.push_back(vector<int>());
        ans[k].push_back(node->val);
        dfs(node->left,k+1,ans);
        dfs(node->right,k+1,ans);
        return ;
    }
    vector<vector<int>> levelOrder(TreeNode *root){
        vector<vector<int>> ans;
        dfs(root,0,ans);
        return ans;
    }
}

leetcode 226:翻转二叉树

翻转根节点-翻转左子树-翻转右子树

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL)return NULL;
        TreeNode *left=invertTree(root->left);
        TreeNode *right=invertTree(root->right);
        root->left=right;
        root->right=left;
        return root;
    }
};
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL)return NULL;
        swap(root->left,root->right);
        invertTree(root->left);
        invertTree(root->right);
        return root;
    }
};

leetcode 107 二叉树层序遍历2

二叉树层序遍历,后直接reverse

class Solution {
public:
    void dfs(TreeNode *root,int k,vector<vector<int>> &ans){
        if(root==NULL) return;
        if(k==ans.size()) ans.push_back(vector<int>());
        ans[k].push_back(root->val);
        dfs(root->left,k+1,ans);
        dfs(root->right,k+1,ans);
        return;
    }
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> ans;
        dfs(root,0,ans);
        //交换
        reverse(ans.begin(),ans.end()); 
        //等价于:
        for(int i=0,j=ans.size()-1;i<j;i++,j--){
            swap(ans[i],ans[j]);//冒泡排序
        }
        return ans;
    }
};

leetcode103 二叉树的锯齿形层序遍历

每一层的节点值按照从左到右的顺序进行排列,但是每一层都是从前一层的右节点开始排列的

class Solution {
public:
    void dfs(TreeNode *root,int k,vector<vector<int>> &ans){
        if(root==NULL) return ;
        if(k==ans.size()) ans.push_back(vector<int>());
        ans[k].push_back(root->val);
        dfs(root->left,k+1,ans);
        dfs(root->right,k+1,ans);
        return ;
    }
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> ans;
        dfs(root,0,ans);
        for(int i=1;i<ans.size();i+=2){ //偶数行都翻转
            // reverse(ans[i].begin(),ans[i].end());
            for(int k=0,g=ans[i].size()-1;k<g;k++,g--){
                swap(ans[i][k],ans[i][g]);
            }
        }

        return ans;
    }
};

leetcode26 :树的子结构

class Solution{
    public:
    bool match_one(TreeNode *A,TreeNode *B){
        if(A==NULL) return B==NULL;
        if(B==NULL) return true;
        if(A->val != B->val) return false;
        return match_one(A->left,B->left) && match_one(A->right,B->right);
    }
    bool isSubstructure(TreeNode *A,TreeNode *B){
        if(A==NULL) return B==NULL;
        if(B==NULL) return false;
        if(A->val == B->val && match_one(A,B)) return true;
        if(isSubstructure(A->left,B)) return true;
        if(isSubstructure(A->right,B)) return true;
        return false;
    }
}
class Solution{
    public:
    bool isSubstructure(TreeNode *A,TreeNode *B){
        return (A!=nullptr && B!==nullptr) && (recur(A,B) || isSubstructure(A->left,B) || isSubstrcture(A->right,B));
    }
    private:
   	bool recur(TreeNode *A,TreeNode *B){
        if(B==nullptr) return true;
        if(A==nullptr || A->val != B->val) return false;
        return recur(A->left,B->left) && recur(A->right,B->right);
}
}

HZOJ 287 合并果子:哈夫曼编码

二叉树的叶子节点*每个叶子节点深度 最后相加

ai * 路径长度,相加

#include <iostream>
#include <set>
using namespace std;
void acm_1_4_shu_hzoj287_test(){
    int n;
    cin>> n;
    set<int> s;

    s.insert(10); //{10}
    cout << *s.begin() <<endl;

    s.insert(8); //{10,8,9}
    cout << *s.begin() <<endl;

    s.insert(9); //{10,8,9}
    cout << *s.begin() <<endl;
}
// 输出:10 8 8 
//set<int> 的begin()每次输出最小值
//s.size() 输出集合有多少个元素
//set不允许有重复元素:用set<pair<int,int>> s避免重复,加一个下标
//
// Created by cry on 2024/3/24.
//
#include <iostream>
#include <set>
using namespace std;
void acm_1_4_shu_hzoj287_test(){
    int n;
    cin>> n;
    set<pair<int,int>> s;

    s.insert(pair<int,int>(10,1));
    cout << s.begin()->first << "," << s.size()<<endl;

    s.insert(pair<int,int>(8,2));
    cout << s.begin()->first << ","<< s.size()<<endl;

    s.insert(pair<int,int>(9,3));
    cout << s.begin()->first<< ","<< s.size() <<endl;
    s.insert(pair<int,int>(9,4));
    cout << s.begin()->first<< ","<< s.size() <<endl;
}
//10,1
//8,2
//8,3
//8,4
#include <iostream>
#include <set>
using namespace std;
typedef pair<int,int> PII
void hzoj287(){
    int n,a;
    set<PII> s;
    cin >> n;
    //输入
    for(int i=0;i<n;i++){
        cin >> a;
        s.insert(PII(a,i));
    }
    int ans=0;
    //开始哈夫曼编码,每次找最小的,然后相加
    for(int i=1;i<n;i++){
        int min1=s.begin()->first;
        s.erase(s.begin());
        int min2=s.begin()->first;
        s.erase(s.begin());
        ans+=min1+min2;
        s.insert(PII(min1+min2,n+i));
    }
    cout << ans << endl;
}

hzoj245:货仓选址

选一个点建立仓库,让所有商店到仓库的距离总和最小

样例输入
5
1 3 5 6 10
样例输出
12
//
// Created by cry on 2024/3/24.
//
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
void acm_1_4_shu_hzoj245(){
    int n,a;
    cin >> n;
    vector<int> arr;
    //输入
    for(int i=0;i<n;i++){
        cin >> a;
        arr.push_back(a);
    }
    //输出每个商店到arr中间中位数的距离,并相加
    sort(arr.begin(),arr.end()); //排序
    int p=arr[n/2],ans=0;
    for(int i=0;i<n;i++){
        ans+=abs(arr[i]-p);
    }
    cout << ans <<endl;
}

cout << s.begin()->first<< ","<< s.size() <<endl;
}
//10,1
//8,2
//8,3
//8,4
#include <iostream>
#include <set>
using namespace std;
typedef pair<int,int> PII
void hzoj287(){
    int n,a;
    set<PII> s;
    cin >> n;
    //输入
    for(int i=0;i<n;i++){
        cin >> a;
        s.insert(PII(a,i));
    }
    int ans=0;
    //开始哈夫曼编码,每次找最小的,然后相加
    for(int i=1;i<n;i++){
        int min1=s.begin()->first;
        s.erase(s.begin());
        int min2=s.begin()->first;
        s.erase(s.begin());
        ans+=min1+min2;
        s.insert(PII(min1+min2,n+i));
    }
    cout << ans << endl;
}

hzoj245:货仓选址

选一个点建立仓库,让所有商店到仓库的距离总和最小

样例输入
5
1 3 5 6 10
样例输出
12
//
// Created by cry on 2024/3/24.
//
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
void acm_1_4_shu_hzoj245(){
    int n,a;
    cin >> n;
    vector<int> arr;
    //输入
    for(int i=0;i<n;i++){
        cin >> a;
        arr.push_back(a);
    }
    //输出每个商店到arr中间中位数的距离,并相加
    sort(arr.begin(),arr.end()); //排序
    int p=arr[n/2],ans=0;
    for(int i=0;i<n;i++){
        ans+=abs(arr[i]-p);
    }
    cout << ans <<endl;
}
【数据结构】(C语言版)第5章:树与二叉树 文章目录一、树的概念1.树的性质2.练习题 一、树的概念 1.树的性质 (5)树的度为m 与m叉树的区别 (6)高度为h的m叉树,至少有h个结点 高度为h、度为m的树,至少有h+m-1个结点 再次体会度为m、与m叉树的不同 2.练习题 ... 阅读详情

相关推荐

考研系列-数据结构第五章:树与二叉树(上)

本文是408考研付费专栏系列-数据结构树与二叉树章节(上半部分),本文详细地总结了树的基本知识点,对树的概念、常见的术语、常用的树的性质进行了总结;对特殊的树结构-二叉树的种类、性质、存储结构、遍历操作的手算和代码实现、线索化进行了总结归纳,并对常见错题进行了整理。

Nelson_hehe的博客 1022

【5】树与二叉树-王道考研

5.1 树 5.1.1 基本概念 树是一种递归的数据结构 每个节点都有唯一的前驱节点 5.1.2 基本术语 5.1.3 树的性质 最小高度:让节点尽可能在低层上分布 5.2 二叉树 5.2.1 基本概念 1. 二叉树 vs 有序树 2. 满二叉树 3. 完全二叉树 定义 性质 4. 二叉排序树 5.平衡二叉树 6. 二叉树的性质 5.2.2 二叉树的存储结构 1. 顺序存储结构 完全二.

jasonyanxx的博客 336

Flowable高级篇 -6.8.0 最全表结构说明-主要表结构字段注释

flowable 28张表 详细

billzhen的博客 1万+

客观题测试-第5章树和二叉树

1、二叉树的深度为k,则二叉树最少有()个结点。A、B、C、2kD、k2、某二叉树的中序序列为ABCDEFG,后序序列为BDCAFGE,则其左子树中结点数目为()A、3B、4C、5D、63、设一棵二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树先序遍历序列为()A、adbceB、decabC、abcdeD、debac解:4、树最适合用来表示()。A、有序数据元素B、无序数据元素C、元素之间具有分支层次关系的数据D、元素之间无联系的数据。

a61233的博客 9533

双RTX 3090实战:如何用vLLM低成本部署Qwen2.5-14B大模型(附避坑清单)

本文详细介绍了如何利用双RTX 3090显卡低成本部署Qwen2.5-14B大模型的完整指南,包括硬件选型、环境配置、vLLM优化及生产环境调优。重点解析了BF16混合精度在显存占用与推理质量上的平衡策略,并提供了实用的避坑清单和性能调优技巧,帮助开发者高效实现大模型部署。

pz890123456的博客 700

STM32F105双路CAN通讯无法进入接收中断问题及解决方法

STM32F105RBT6双路CAN通讯无法进入接收中断问题及解决方法

m0_62383223的博客 3442

实验4:树和二叉树

数据结构头歌实验答案

2201_75694648的博客 914

最新CobaltStrike4.8/CobaltStrike4.9、CS4.9/CS4.8、 Windows/Linux/Mac版下载

Cobalt Strike是一款基于java的渗透测试神器,常被业界人称为CS神器。自3.0以后已经不在使用Metasploit框架而作为一个独立的平台使用,分为客户端与服务端,服务端是一个,客户端可以有多个,非常适合团队协同作战,多个攻击者可以同时连接到一个团队服务器上,共享攻击资源与目标信息和sessions,可模拟APT做模拟对抗,进行内网渗透。 Cobalt Strike集成了端口转发、服务扫描,自动化溢出,多模式端口监听,win exe木马生成,win dll木马生成,java木马生成,

weixin_43167326的博客 7972

第7章树和二叉树:二叉树、树、森林之间的转换

摘要:本文介绍了树、森林与二叉树之间的相互转换方法。树转换为二叉树遵循"左孩子右兄弟"规则;森林转换则是将各树转为二叉树后,将后序二叉树的根结点作为前一棵的右孩子。还原过程与之相反。通过这种一一对应关系,可以将复杂的树结构问题简化为二叉树问题处理,展现了二叉树在树结构应用中的重要性。文中通过多个具体实例,配以图解详细说明了各类转换的操作步骤和实现原理。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 771

openclaw本地模型对接

使用是官方推荐的一种集成方式,它可以简化配置过程。但由于您的系统环境和之前复杂的配置历史,我为您梳理了一个核心流程,并增加了关键的“事后检查”步骤,以确保能从根本上解决问题。

suny8的专栏 2463

【我的Android进阶之旅】Android自定义View实现一个游戏摇杆,来实现监听遥动的方向或者监听摇动的角度的功能

一、需求描述 去年有个需求,需要使用自定义View实现一个游戏摇杆,来识别上下左右摇动的方向。 有点类似下面这样的王者荣耀游戏摇杆的效果 二、业界已有的参考资料 在下面这篇博客介绍了如何自定义游戏摇杆 2.1 博客介绍 Android自定义摇杆 2.1.1 功能 支持自适应大小 支持2个方向、4个方向、8个方向的摇动监听 支持摇动角度获取 可选回调模式 支持可摇动区域自定义 支持摇杆自定义 支持设置图片、色值、Shape图形 2.1.2 效果图 2.1.3 设置回调方式 setCallBac

字节卷动 1409

第7章树和二叉树:二叉树的存储结构

本文介绍了二叉树的两种存储结构:顺序存储和链式存储。顺序存储通过补全成完全二叉树后按层序编号存储,仅适用于完全二叉树;链式存储则采用二叉链表(含左右孩子指针)或三叉链表(增加双亲指针),其中n个结点的二叉链表存在n+1个空指针域。通过例题分析,阐明了如何计算指向孩子结点的指针数量。文章还给出了两种存储方式的具体C语言实现代码。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 1272

LSTM 双向 Bi-LSTM

LSTM 双向 Bi-LSTM

jacke121的专栏 1518

第7章树和二叉树:根据遍历序列确定二叉树

摘要:本文介绍了如何通过二叉树的遍历序列唯一确定二叉树结构。定理表明,中序序列与先序或后序序列的组合可以唯一确定二叉树,而先序和后序序列则不能。通过具体示例(先序ABDGCEF,中序DGBAECF)详细演示了构造二叉树的递归过程。此外,文中解析了三道典型例题,涉及不同遍历序列之间的关系及其应用,如判断结点位置、确定根结点右孩子等。这些内容为理解二叉树遍历序列的相互关系及其在树结构确定中的应用提供了实践指导。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 1343

开源免费!ReaLTaiizor如何用MIT许可证打造专业级WinForm UI?

摘要: ReaLTaiizor是一款开源UI控件库,为WinForm应用提供现代化界面解决方案。支持100+组件、多主题切换(浅色/深色/自定义)和.NET 4.8-8.0全版本兼容,MIT许可证允许免费商用。通过NuGet快速安装,3步改造传统界面:1)注入主题(如this.Theme = new Dark()),2)替换原生控件为高颜值组件(如ModernGrid替代DataGridView),3)集成高级功能(分页/动画提示)。典型场景包括登录界面美化(进度动画+通知控件)和数据表格Material风

墨夶的博客 1521

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

第7章树和二叉树:遍历二叉树之中序遍历

本文介绍了二叉树遍历的概念和基本方法。遍历是指按照特定顺序访问树中每个节点一次的操作,将非线性结构转化为线性序列。根据访问根节点的时机,主要分为先序、中序、后序三种遍历方式,以及层次遍历。文中重点阐述了中序遍历的递归和非递归算法实现,通过"左根右"的访问顺序,详细说明了非递归算法利用栈结构处理节点的步骤过程,并给出算法描述。分析表明,各种遍历算法的时间复杂度均为O(n),空间复杂度在最坏情况下也为O(n)。遍历操作是二叉树其他运算的基础。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 1718

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

第7章树和二叉树:哈夫曼树

哈夫曼树是一种带权路径长度最短的二叉树,用于数据压缩等领域。其核心概念包括路径长度、权值、带权路径长度等。构造哈夫曼树的算法采用贪心策略:首先将n个权值作为n棵单结点树,每次选择权值最小的两棵树合并,直到只剩一棵树。该树具有2n-1个结点,可用数组存储。哈夫曼树的特点是权值大的结点靠近根节点,从而最小化树的带权路径长度。通过示例展示了给定权值集合时哈夫曼树的构造过程和WPL计算方法。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 923

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

第7章树和二叉树:二叉树遍历算法的应用

本文介绍了二叉树的几种基本操作算法:1) 二叉链表的创建,通过先序遍历递归构建,用"#"表示空结点;2) 二叉树复制,采用类似先序遍历的递归方式;3) 计算二叉树深度,基于后序遍历比较左右子树深度;4) 统计结点总数,递归累加左右子树结点;5) 统计不同度(0,1,2)的结点数量,通过递归遍历判断子结点情况。所有算法均采用递归实现,体现了二叉树操作的典型递归特性。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 763

数据结构第6章树和二叉树:单元测试28题全解析(含叶子结点数、遍历序列重构、哈夫曼树、完全二叉树)

本文摘要:本章测试题主要考察二叉树的基本概念和性质,包括结点计算(如叶子结点数=双分支结点数+1)、遍历序列关系(先序/中序/后序)、完全二叉树特性(结点编号规律)、哈夫曼树构造(带权路径长度计算)等。重点内容涉及:1)二叉树度与结点关系(度为0的结点=度为2的结点+1);2)遍历序列确定树结构;3)完全二叉树的层结点计算(第k层最多2^(k-1)个结点);4)哈夫曼树的特性(n个叶子对应2n-1个结点)。测试题通过具体数值计算和概念判断强化了对二叉树结构的理解。

深耕计算机专业知识与技术。 376

java数据结构 第10章树--结构的基础部分02 顺序储存二叉树、线索化二叉树

文章目录10.2 顺序存储二叉树10.2.1 顺序存储二叉树的概念1.基本说明2.要求:3.顺序存储二叉树的特点:10.2.2 顺序存储二叉树遍历1.代码实现:2.运行结果3.课后作业10.2.3 顺序存储二叉树应用实例10.3 线索化二叉树10.3.1 先看一个问题10.3.2 线索二叉树基本介绍10.3.3 线索二叉树应用案例1.思路分析:2.代码实现:3.运行结果:10.3.4 遍历线索化二叉树2) 分析:3) 代码:4) 运行结果10.3.5 线索化二叉树的课后作业:【学习笔记】【学习资料】 10.

学无止境,勤则可达;志存高远,恒亦能成! 598

第7章树和二叉树:树的存储结构

本文介绍了树的三种常用存储结构:双亲表示法、孩子表示法和孩子兄弟法。双亲表示法采用顺序存储,记录每个结点的双亲位置,便于查找双亲和根结点;孩子表示法通过多重链表或孩子链表记录结点的孩子信息,有不同实现方式;孩子兄弟法(二叉链表表示法)则用两个指针分别指向第一个孩子和下一个兄弟结点,便于转换为二叉树进行操作。三种方法各有特点,适用于不同场景的树结构存储需求。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 823

第7章树和二叉树:树的基本概念

本文介绍了树的基本ancy的基本概念和术语。树是由n(n≥0)个结点组成的有限集合,具有递归定义特性,由根结点和若干互不相交的子树构成。文章阐述了四种树的逻辑表示方法:树形图、嵌套集合、广义表和凹入形式。重点解释了树的基本术语,包括结点、度、叶子、双亲/孩子、兄弟、祖先/子孙、层次、深度等概念,并区分了有序树和无序树。最后指出森林是m(m≥0)棵互不相交树的集合,并给出了树的二元组逻辑结构定义。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 752

第7章树和二叉树:遍历二叉树之先序后序和层序遍历

本文介绍了二叉树的三种遍历方法:先序遍历、后序遍历和层次遍历。先序遍历按照"根左右"的顺序访问结点,后序遍历遵循"左右根"的顺序,而层次遍历则是按层从左到右访问结点。每种遍历方式都有其递归算法实现,其中先序和后序遍历的第一个和最后一个元素分别为树的根结点。这些遍历方法在二叉树的操作中具有重要作用,能够以不同顺序访问树中的结点。

计算机科学、人工智能、数据分析和大数据方向的研发和教学。 351

构建一颗二叉树 java_java实现二叉树的构建

java实现树目录_计算机软件及应用_IT/计算机_专业资料。一:树节点的定义(...Java编程题:根据二叉树的前序遍历序列_计算机软件及应用_IT/计算机_专业资料。剑指offer,根据二叉树前序遍历和中序遍历序列,重建二叉树,并求后序遍历序列。Java......链式存储结构和递归算法本身就是两个难 建立二叉树需要将它们有机结合。 点,建立二叉树需要将它们有机结合。《数据结构(Java版)(...

weixin_35663151的博客 622

数据结构(第4章: 树和二叉树)

创建二叉树、先序遍历 、中序遍历、后序遍历、层序遍历二叉树

瓦釜苑 601
上一篇: 第2章顺序表与链表
下一篇: 第14章动态规划
厨 神
博客等级 码龄8年 263粉丝 78原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厨 神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值