第4章树与二叉树

属于二叉树

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

所以直接改变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 10for (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 10Node *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 128using 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每个子树的前序遍历结果 给tempvector<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==0int 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 Noneroot_val = preorder[0]root_index = inorder.index(root_val) #在中序遍历中找到根节点# while(inorder[pos]!=preorder[0]):pos+=1;root = TreeNode(root_val)# 左子树是1:pos 0:posroot.left = self.buildTree(preorder[1:root_index+1], inorder[:root_index])# 右子树是:pos+1:n  pos+1:nroot.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; //队列,类型为TreeNodevector<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;
}

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

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

相关文章

数字化时代下的电子元器件商城模式创新

在数字化时代&#xff0c;电子元器件商城可以通过以下方式进行模式创新&#xff1a; 智能化搜索与推荐&#xff1a; 引入人工智能和机器学习技术&#xff0c;提供智能化搜索和个性化推荐功能&#xff0c;根据客户的需求和历史购买记录推荐相关的电子元器件&#xff0c;以提高购…

全国植被类型分布数据

引言 全国植被类型分布数据利用 Landsat 卫星数据&#xff08;Landsat TM&#xff0c;ETM和 OLI&#xff09;完成了长时序的地表覆盖变化检测&#xff0c;并结合变化 检测结果实现了逐区域和逐期的地表覆盖动态更新&#xff0c;30米精细植被类型分布数据&#xff0c;共包含 2…

Java 总结二

一、抽象类和接口 抽象类使用abstract修饰&#xff0c;不能实例化。抽象类中可以有零到多个抽象方法。抽象方法使用abstract关键字修饰&#xff0c;没有方法体。如果非抽象类继承抽象类&#xff0c;则必须实现父类的所有的抽象方法&#xff0c;否则子类还是一个抽象类。用fina…

Python爬虫之爬取网页图片

当我们想要下载网页的图片时&#xff0c;发现网页的图片太多了&#xff0c;无从下手&#xff0c;那我们写一个脚本来爬取呗。 这次的脚本是专门针对某个外国网站使用的&#xff0c;因此仅供参考思路。 在测试的过程中&#xff0c;我发现网站使用了发爬虫机制&#xff0c;具体就…

FPGA工程师及其相关岗位招聘~

社区的招聘功能上线之后&#xff0c;许多企业都在上面发布了招聘岗位。 目前有30企业&#xff0c;岗位围绕FPGA工程师&#xff0c;涵盖嵌入式软件工程师、射频工程师、C语言开发、BMC工程师等等&#xff0c;入口放在这里&#xff1a;F学社-全球FPGA技术提升平台 登录账号后&a…

<QT基础(1)>对象树结构

在Qt中&#xff0c;当你将一个对象设置为另一个对象的子对象时&#xff0c;Qt会自动管理它们的生命周期&#xff0c;包括子对象在堆上分配的内存空间。这意味着&#xff0c;如果你使用 new 在堆上创建了一个子对象&#xff0c;并将其设置为另一个对象的子对象&#xff0c;当父对…

海思 Hi3536AV100 简介

海思 Hi3536AV100 简介 Hi3536AV100 是针对多路高清/超高清&#xff08;1080p/4M/5M/4K&#xff09;智能NVR产品应用开发的新一代专业高端SoC芯片。集成了ARM Cortex-A55八核处理器和性能强大的神经网络处理器&#xff0c;支持多种智能算法应用。支持32路1080p多协议解码及4路…

OpenFoam最全总结

一、OpenFOAM用户指南-9(中文版)&#xff1a;这个里面用中文写了OpenFOam相关的基础知识和文件结构和基础语法&#xff0c;包括安装、使用、案例、paraview可视化等&#xff0c;是最全的的一个文档。 http://www.dyfluid.com/theory.pdf 二、无痛苦N-S方程笔记&#xff08;东岳…

深入浅出(五)QtPropertyBrowser库—属性编辑器

文章目录 1. QtPropertyBrowser简介1.1 下载 2. 编译和部署&#xff1a;3. C示例 1. QtPropertyBrowser简介 QtPropertyBrowser是一个第三方库&#xff0c;用于在Qt应用程序中显示和编辑属性。它不是Qt框架的一部分&#xff0c;但可以与Qt一起使用。 1.1 下载 GitHub地址&am…

URL是什么?(概念+应用场景+优缺点)

1、概念 URL&#xff08;Uniform Resource Locator&#xff09;是统一资源定位符的缩写&#xff0c;简称网址。 用于指定网络上的资源的位置和访问方式。 它包含了资源的协议、主机名、路径等信息&#xff0c;可以唯一标识互联网上的资源。 2、作用&#xff1a; ① 定位资…

HCIP-Datacom(H12-821)题库补充(3/27)

最新 HCIP-Datacom&#xff08;H12-821&#xff09;完整题库请扫描上方二维码访问&#xff0c;持续更新中。 运行OSPF协议的路由器&#xff0c;所有接口必须属于同一个区域。 A&#xff1a;正确 B&#xff1a;错误 答案&#xff1a;B 解析&#xff1a;OSPF的邻居关系是基于…

Python环境下滚动轴承状态监测与故障诊断(NASA IMS轴承数据集)

智能维护系统IMS)滚动轴承数据是美国辛辛那提大学智能维护系统中心提供的全寿命周期数据&#xff0c;轴上安装了4个轴承。通过摩擦带将转速保持恒定在 2000r/min。包含3个数据集&#xff0c;每个数据集描述了一个测试到失败的实验。其中第一个实验装置的数据采集从 2003 年 10月…

鸿蒙OS开发实例:【工具类封装-emitter组件间通信】

import Emitter from ohos.events.emitter; import pasteboard from ohos.pasteboard; MyEmitterUtil 是一个针对 HarmonyOS 的事件驱动编程封装类&#xff0c;主要用于组件间的通信和数据传递。 使用要求&#xff1a; DevEco Studio 3.1.1 Release 或更高版本API 版本&…

get 请求中传递数组参数

文章目录 问题分析 问题 使用get请求传参时有参数是数组 分析 qs.stringify({ a: [b, c] }, { arrayFormat: indices }) // 输出结果&#xff1a;a[0]b&a[1]c qs.stringify({ a: [b, c] }, { arrayFormat: brackets }) // 输出结果&#xff1a;a[]b&a[]c qs.stringif…

Qt C++ | QTimer经验总结

QTimer Class QTimer类提供重复计时器和单次计时器 头文件: #include <QTimer> qmake: QT += core 继承自: QObject 定时器信号 void timeout() 公共函数 Qt::TimerType 枚举定义了 Qt 中不同类型的定时器。它包含以下值: **Qt::PreciseTimer:**高精度定时器,用…

国内ip地址推荐,畅享网络新体验!

在数字化时代&#xff0c;IP地址不仅是网络连接的基石&#xff0c;也是互联网产业发展的重要标志。国内作为全球互联网市场的重要参与者&#xff0c;拥有众多IP地址资源。虎观代理小二旨在探索并推荐一些国内IP地址&#xff0c;分析它们的价值所在&#xff0c;并探讨如何更好地…

hcia datacom课程学习(4):ICMP与ping命令

1.什么是ICMP ICMP是ip协议的一部分&#xff0c;常用的ping命令就是基于icmp协议的。 在防火墙策略中也能看到ICMP&#xff0c;如果将其禁用&#xff0c;那么其他主机就ping不通该主机了 2. ICMP数据报 2.1数据报构成 ICMP协议的报文包含在IP数据报的数据部分&#xff0c; …

[windows]Windows上缩放窗体的两种方式

第一种 直接上图 第二种 第二种方式时&#xff0c;快速拖动时&#xff0c;如果是chrome浏览器套壳软件就会出现拖动部分出现黑边的现象而原生的桌面应用程序则不会出现黑边。这现象在chrome浏览器本身就存在。如图 typora是用electron写的软件存在该问题

FastAPI+React全栈开发07 MongoDB数据库的结构

Chapter02 Setting Up the Document Store with MongoDB 02 The structure of a MongoDB database FastAPIReact全栈开发07 MongoDB数据库的结构 MongoDB is arguably the most used NoSQL database today, its power, ease of use, and versatility make it an excellent c…

区块链与智能合约

什么是区块链 要想理解什么区块链&#xff0c;我们先来从本质上认识一下它 区块链&#xff1a;本质上是一个去中心化的分布式账本数据库&#xff0c;是指通过去中心化和去信任的方式集体维护一个可靠数据库的技术方法。 没有基础的人可能理解起来有点困难&#xff0c;我们来…