属于二叉树
跟链表的不同:每个节点可以指向多个节点
所以直接改变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) ->
- 遇到关键字就生成新的节点
- 遇到左括号就把新生成的节点压入栈
- 遇到 逗号 , **标记(flag)**当前处理右子树了
- 遇到右括号就将栈顶元素出栈
- 每次生成一个新的节点的时候根据标记设置栈顶元素的左右子树
//
// 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;
}