文章目录
- 1.二叉树深度 [必会]
- 2.该树是否为平衡二叉树 [必会]
- 3.权路径长度WPL [必会]
- 4.层次遍历二叉树 [必会]
- 5.二叉树从根节点到叶结点的最长路径上的所有结点
- 6.给定两个整数,输出两者所在层数间隔数(非递归函数实现)
- 7.用先序遍历二叉树的每一个结点的深度并输出
- 8.哈夫曼树的叶子结点的个数(递归实现)
- 9.找树中的key值点
- 10.往二叉排序树插入新节点 [掌握]
- 11.求二叉平衡树的平衡因子 [掌握]
- 12.二叉树中的所有结点个数
- 13.二叉树所有叶子结点个数
- 14.两个二叉树是否相似
- 15.二叉树左右子树交换
- 16.输出先序遍历的第k个结点
- 17.将叶子结点串成单链表
- 18.增加双亲结点指针,并赋值,输出所有结点到根节点的路径
- 19.求二叉树中值为x的层号
- 20. 求解二叉树的宽度
- 21. 先序非递归遍历 [必会]
- 22.中序非递归遍历 [必会]
- 23.后序非递归 [必会]
- 24.输出根节点到每个叶子结点的路径
- 25.二叉树顺序方式存储转化为二叉链表方式
- 26.查找值为x的结点,并打印出x的所有祖先
- 27.找到p和q最近公共祖先结点r
- 28.自下而上从右到左的层次遍历
- 29.二叉树是否为完全二叉树
- 30.对树中每个元素为x的结点,删除以它为根的子树,并释放空间
- 31.判断是否为二叉排序树
- 32.数组顺序构造一棵二叉树
- 33.求编号i和j的最近公共祖先结点的值
1.二叉树深度 [必会]
//第一种递归写法 没有用三元运算符
int Deepth(TreeNode *root){
if(!root) return 0;
return max(Deepth(root->left),Deepth(root->right))+1;
}
//第二种递归写法 也可以直接计算二叉树深度
int Deepth(TreeNode *root){
return root?max(Deepth(root->left),Deepth(root->right))+1:0;
}
求哈夫曼树、二叉树宽度等都要运用深度的模板
三元运算符的语法为:条件表达式?表达式1:表达式2。
说明:问号前面的位置是判断的条件,判断结果为bool型,为true时调用表达式1,为false时调用表达式2。
2.该树是否为平衡二叉树 [必会]
//递归调用,查找深度
int Deepth(TreeNode *root){
return root?max(Deepth(root->left),Deepth(root->right))+1:0;//如果该节点不为空,那么就返回该结点左右孩子深度的最大值并加上该节点本层的初始高度1,即为该结点深度
}
Bool isBalanced(TreeNode *root){
if(!root) return true;
//平衡二叉树是左右孩子树的高度差为0或1
if(abs(Deepth(root->left)-Deepth(root->right))<=1&&isBalanced(root->left)&&isBalanced(root->right))
return true;
return false;
}
3.权路径长度WPL [必会]
int WPL=0;
int WPL(TreeNode *root){
PreOrder(root,1);
return WPL;
}
//先序遍历求权值
void PreOrder(TreeNode *root,int level){
if(!root) return;
if(!root->left&&!root->right)
WPL=WPL+root->weight*(level-1);//加入的是左右子树都有孩子的结点的权值
PreOrder(root->left,level+1);
PreOrder(root->right,level+1);
}
4.层次遍历二叉树 [必会]
//更偏向于Java的代码,直接创建的队列
void LevelOrder(TreeNode *root) {
Queue Q; //创建层次遍历队列
//如果树是空就返回
if (!root) return;
Q.push(root);
//当队列不为空时
while (!Q.empty()) {
//这里的队列长度其实是一直变化的,比如根节点时是1,但是根据后面的判断,会有新的元素入队
//这样就导致在新的一轮循环来临的时候,长度就已经改变了
int len = Q.size();
for (int i = 0;i < len;i++) {
//输出后弹开队头元素
visit(Q.front);
TreeNode *temp=Q.front;
Q.pop();
//向该结点的左右子树继续访问并入队
if (temp->left)
Q.push(temp->left);
if (temp->right)
Q.push(temp->right);
}
}
}
//数组完善,用数组实现队列来实现层次遍历
void LevelOrder(TreeNode *p){
int front,rear=0;//队列的头尾指针
TreeNode *que[MaxSize];//初始化队列
TreeNode *q;
if(p!=NULL){
rear=(rear+1)%MaxSize;//入队操作
que[rear]=p;
while(front!=rear){//出队操作
front=(front+1)%MaxSize;
q=que[front];
visit(q);
if(q->lchild!=NULL)//左右孩子入队
rear=(rear+1)%MaxSize;
que[rear]=q->lchild;
}
if(q->rchild!=NULL){
rear=(rear+1)%MaxSize;
que[rear]=q->rchild;
}
}
}
5.二叉树从根节点到叶结点的最长路径上的所有结点
//借1.二叉树深度 [必会]的模板
void LongestPath(TreeNode *root) {
while (!root) {
cout << root->data << endl;
if (Deepth(root->left) > Deepth(root->right))
LongestPath(root->left);
else
LongestPath(root->right);
}
}
int Deepth(TreeNode *root) {
root ? Max(Deepth(root->left),Deepth(root->right)) + 1 : 0;
}
6.给定两个整数,输出两者所在层数间隔数(非递归函数实现)
//题目完整信息:对给定的两个整数,若两个都不是树中的元素,输出-2;若仅有一个不是树中的元素,输出-1;若两个都是树中的元素,输出两者所在层数的间隔数;(非递归函数实现)
int levelOrder(TreeNode *root,int a,,int b) {
Queue Q;
int level1 = 0, level2 = 0,nowlevel = 0;//level1是a的层数,level2是b的层数,nowlevel是遍历的层数
if (!root) return -2;//树为空,返回-2
Q.push(root);//将根节点入队
while (!Q.empty()) {
int len = Q.size();
for (int i = 0;i < len;i++) {
TreeNode *temp = Q.front();
if (a == temp->data)
level1 = nowlevel;
if (b == temp->data)
level2 = nowlevel;
Q.pop();
nowlevel++;//遍历的高度+1
if (temp->left)
Q.push(temp->left);
if (temp->right)
Q.push(temp->right);
}
}
if (level1 == 0 && level2 == 0)
return -2;
if (level1 == 0 || level2 == 0)
return -1;
return abs(level1-level2);
}
7.用先序遍历二叉树的每一个结点的深度并输出
//这里是采用前序遍历来访问各个结点
void PreOrder(TreeNode *root,int level){
if(!root) return;
count<<level<<endl;//输出该节点的深度值
PreOrder(root->left,level+1);
PreOrder(root->right,level+1);
}
//处理第一个结点的深度,需要将根节点的深度特殊化
void PrintLevel (TreeNode *root){
PreOrder(root,1);
}
8.哈夫曼树的叶子结点的个数(递归实现)
//时间复杂度为O(n)
typedef struct Node{
int x;
struct Node* left;
struct Node* right;
}Node,*TreeNode
int NumLeeaf(TreeNode *root){
if(!root) return 0;//如果此树是空 则返回0
if(root->left==null){
return 1+NumLeaf(root->right);//由于哈夫曼树的特性,如果左节点是空,那么就有一个叶子节点,然后开始探索该访问节点的兄弟子树的叶子节点的个数
}
else{
return NumLeaf(root->left)+NumLeaf(root->right);//该节点如果不是叶节点的父节点,那么继续左右子树遍历
}
}
9.找树中的key值点
Bool FindKey(TreeNode *p,int key){
if(p!=NULL){
if(p->data==key) return true;
}else{
FindKey(p->lchild,key);
FindKey(p->rchild,key);
}
return false;
}
10.往二叉排序树插入新节点 [掌握]
//定义二叉排序树结点
typedef struct Node{
int data;
struct Node* lchild;
struct Node* rchild;
}Node,*TreeNode;
TreeNode root=NULL;
//二叉排序树插入新节点(非递归)
void InsertSortTree(TreeNode &root,int data){
//创立新的结点,将插入值给新节点
TreeNode p=(TreeNode)malloc(sizeof(Node));
p->data=data;
p->lchild=NULL;
p->rchild=NULL;
//如果该二叉排序树为空
if(root==null) {
root=p;
return;
}
//parent结点为记录插入位置,q为工作指针
TreeNode q=root,parent;
do{
parent=q;
if(parent->data>data)//比较值的大小
q=parent->lchild;
else
q=parent->rchild;
}while(q!=NULL);
if(parent->data>data)
parent->lchild=p;
else
parent->rchild=p
}
//二叉排序树插入新节点(递归)
void InsertSortTree(TreeNode &root,int data){
if(root==NULL){
//递归时,若查到结点为null时,就是该data插入的地方
TreeNode p=(TreeNode)malloc(sizeof(Node);
p->data=data;
p->lchild=NULL;
p->rchild=NULL;
t=p;
return;
}else if(root->data>data)
InsertSortTree(root->lchild,data);
else
InsertSortTree(root->rchild,data);
}
11.求二叉平衡树的平衡因子 [掌握]
//构造新的结点去判断平衡二叉树
typedef struct Node{
struct Node *lchild;
struct Node *rchild;
int bf;//平衡因子
char data;
}Node,TreeNode;
int Height(TreeNode *root){
int hl,hr;
if(root==NULL){
return 0;
}else{
hl=Height(root->lchild);
hr=Height(root->rchild);
if(hl>hr)
return hl+1;
else
return hr+1;
}
}
void Balanced(TreeNode *root){
if(!root){
Balanced(root->lchild);
Balanced(root->rchild);
int hl=Height(root->lchild);
int hr=Height(root->rchild);
root->bf=abs(hl-hr);
}
}
12.二叉树中的所有结点个数
//方法一:
int count(TreeNode *p){
int num_left,num_right;
if(p==NULL)
return 0;
else{
num_left=count(p->lchild);//左子树的结点个数
num_right=count(p->rchild);//右子树的结点个数
return num_left+num_right;
}
}
//方法二:
int num=0;
int count(TreeNode *p){
if(p!=NULL){
num++;
count(p->lchild);
count(p->child);
}
}
13.二叉树所有叶子结点个数
//法一:
int count(TreeNode *p){
int num_left,num_right;
if(p==NUll)
return 0;
if(p->lchild==NULL&&p->rchild==NULL)
return 1;
else{
num_left=count(p->lchild);
num_right=count(p->rchild);
return num_right+num_left;
}
}
//法二:
int num=0;
int count(TreeNode *p){
if(p->rchild==NULL&&p->lchild)
num++;
else{
count(p->lchild);//左子树的叶节点
count(p->rchild);//右子树的叶节点
}
}
14.两个二叉树是否相似
指都为空或者都只有一个根节点,或者左右子树都相似
int similar(TreeNode *T1,TreeNode* T2){
int left,right;
if(T1==NULL&&T2==NULL)
return 1;
if(T1==NULL||T2==NULL)
return 0;
else{
left=similar(T1->lchild,T2->lchild);
right=similar(T1->rchild,T2->rchild);
return left&&right;
//return similar(T1->lchild,T2->lchild)&&similar(T1->rchild,T2->rchild);
}
}
15.二叉树左右子树交换
void swap(TreeNode *p){
if(p!=NULL){
swap(p->lchild);
swap(p->rchild);
//找到要交换的最底层子树
TreeNode *temp=p->lchild;
p->lchild=p->rchild;
p->rchild=temp;
}
}
16.输出先序遍历的第k个结点
int n=0;
void print(TreeNode *p,int k){
if(p!=NULL){
n++;
if(k==n) {//找到第k个
printf("%d",p->data);
return;
}
print(p->lchild,k);
print(p->rchild,k);
}
}
17.将叶子结点串成单链表
题目完整信息:利用结点的右孩子指针将一个二叉树的叶子结点从左向右连接成一个单链表(head指向第一个,tail指向最后一个)
void link(TreeNode *p,TreeNode *&head,TreeNode *&tail){
if(p!=NULL){
if(!p->lchild&&!p->rchild){
//遍历到第一个叶子结点
if(head==NULL){
head=p;//头尾都指向了第一个叶子结点
tail=p;
}
else{
//如果该叶子结点不是第一个叶子结点了,就利用叶子结点的右孩子为空,将上一个叶子节点右孩子指针指向现在的叶子结点
tail->rchild=p;//链表尾插法
tail=p;
}
}
link(p->lchild,head,tail);
link(p->rchild,head,tail);
}
}
18.增加双亲结点指针,并赋值,输出所有结点到根节点的路径
typedef struct BTNode{
char data;
struct BTNode *parent,lchild,rchild;
}BTNode;
//增加父母指针
void addParent(BTNode *p,BTNode *q){
if(p!=NULL){
p->parent=q;
q=p;
//传入一个结点,和它的孩子结点
addParent(pre,q->lchild);
addParent(pre,q->rchild);
}
}
//在以上的基础上,输出每个结点到根节点的路径
void allpath(BTNode *p){
if(p){
printpath(p);
allpath(p->lchild);
allpath(p->rchild);
}
}
void printpath(BTNode *p){
while(p!=NULL){
printf("%c",p->data);
p=p->parent;
}
}
19.求二叉树中值为x的层号
int deep=1;
void Deepth(TreeNode *root,int x){
if(root){
if(root->data==x){
printf("%d",deep);//不输出该层号,可以直接return
return;
}
deep++;
Deepth(root->lchild,x);
Deepth(root->rchild,x);
deep--;//往后面回退再次查询的时候 层数减一
}
}
20. 求解二叉树的宽度
//法一:
typedef struct{
BTNode *p;
int Ino;//Ino是层数号,
}St;//队列的结构体
int maxNode(BTNode *root){
St que[maxsize];//建一个队列来实现层序遍历
int front=0,rear=0;//队列的头尾指针
int Ino=0;//来记录当前层数号
if(root!=NULL){
que[++rear].p=root;//将根节点入队
que[rear].Ino=1;//根节点为第一层
while(front!=rear){
BTNode *q=que[++front].p;
Ino=que[front].Ino;
if(q->lchild!=NULL){
que[++rear].p=q->lchild;//左孩子入队
que[rear].Ino=Ino+1;//同时层数号+1
}
if(q->rchild!=NULL){
que[++rear].p=q->rchild;//右孩子入队
que[rear].Ino=Ino+1;//同时层数号在原有基础上+1
}
}
int max=0,n;//max'统计当前最大的宽度,n统计一层有多少个结点即这一层的宽度
for(int i=1;i<=que[rear].Ino;i++){//开始用层数来遍历队列
n=0;//每一层结束后都要将n归为0
for(int j=1;j<=rear;j++)//
if(que[j].Ino==i)
++n;//如果是第i层,则n+1
if(max<n) max=n;
}
return max;
}
else return 0;
}
//法二:个人更喜欢法二,更清晰
int MaxFindWidth(TreeNode *p){
int max=0;
int width=0;
int high=FindDeepth(p);//这颗树最大的高度
for(int i=1;i<=high;i++){//开始经过每一层的遍历
width=FindWith(p,i);
if(max<width)
max=width;
}
}
int FindWidth(TreeNode *p,int level){//
if(p==NULL)
return 0;
else{
if(level==1)
return 1;
else
return FindWidth(p->lchild,level-1)+FindWidth(p->rchild,level-1);
}
}
int FindDeepth(TreeNode *p){
return p?Max(FindDeepth(p->lchild),FindDeepth(p->rchild))+1:0;
}
21. 先序非递归遍历 [必会]
void PreOrder(TreeNode *root){
if(root!=NULL){
int top=-1;
TreeNode *Stack[MaxSize];
TreeNode *p;
Stack[++top]=root;
while(top!=-1){
p=stack[top--];
visit(p);
if(p->rchild!=NULL)
Stack[++top]=p->rchild;
if(p->lchild!=NULL)
Stack[++top]=p->lchild;
}
}
}
22.中序非递归遍历 [必会]
void inNonrecursion(TreeNode *p){
if(!p){
TreeNode *Stack[MaxSize];
int top=-1;
while(top!=-1||!root)
while(!p){//这一轮循环等于是把左子树的左孩子都压栈了
Stack[++top]=p;//先入根节点
p=p->lchild;//再入左孩子
}
if(top!=-1){//开始输出并让右子树右孩子入栈
p=Stack[top--];
visit(p);
p=p->rchild;
}
}
}
23.后序非递归 [必会]
//还是采用王道的比较好,后面方法总觉得有点问题
void PostOrder(BiTree T){
InitStack(S);
p=T;
r=NULL;
while(p||!IsEmpty(S)){
if(p){
push(S,p);
p=p->lchild;
}
else{
GetTop(S,p);
if(p->rchild&&p->rchild!=r)
p=p->rchild;
else{
pop(S,p);
if(p->rchild&&p->rchild!=r)
p=p->rchild;
else{
pop(S,p);
visit(p->data);
r=p;
p=NULL;
}
}
}
}
}
//法一:引用新定义结点遍历
typedef struct{
BTNode *t;//储存结点
int tag;//判断遍历次数 0是第一次 1是第二次
}
void postNonrecursion(BTNode *bt){
Stack stack[];
int top=-1;
while(bt!=NULL||top!=-1){
while(bt!=NULL){
stack[++top]=bt;
stack[top].tag=0;
bt=bt->lchild;
}
while(top!=-1&&stack[top].tag==1){
visit(stack[top].t->data);
top--;
}
if(top!=-1){
stack[top].tag=1;
bt=stack[top].t->rchild;
}
}
}
//法二:利用双栈来实现后序遍历
void postNonrecursion(BTNode *bt){
if(bt!=NULL){
BTNode *Stack1[MaxSize];
BTNode *Stack2[MaxSize];
int top1=-1,top2=-1;
BTNode *p=NULL;
Stack1[++top1]=p;
while(top1!=-1){
p=Stack[top1--];
Stack[++top2]=p;
if(p->lchild!=NULL)
stack1[++top1]=p->lchild;
if(p->rchild!=NULL)
stack[++top1]=p->rchild;
}
while(top2!=-1){
p=stack[top2--];
visit(p);
}
}
}
24.输出根节点到每个叶子结点的路径
int i,top=0;
char pathstack[maxsize];
void allpath(BTNode *p){
if(p!=NULL){
pathstack[top++]=p->data;
if(!p->lchild&&!p->rchild)
for(i;i<top;i++)
printf("%c",pathstack[i]);
allpath(p->lchild);
allpath(p->rchild);
--top;
}
}
25.二叉树顺序方式存储转化为二叉链表方式
//i为起始下标,n为个数
Bitree create(charA[],int i,int n){
if(i>j)
t=NULL:
else{
t=(BTNode*)malloc(sizeof(BTNode));
t->data=A[i];
t->lchild=create(A,2*i,n);
t->rchild=create(A,2*i+1,n);
return t;
}
}
26.查找值为x的结点,并打印出x的所有祖先
//类比后序遍历的非递归实现,这里主要是将后序遍历的出口的条件改正了
typedef struct{
BTNode *t;
int tag;
}Stack;
void Search(BTNode *bt,int x){
Stack stack[];
int top=-1;
while(bt!=NULL||top!=--1){
while(bt!=NULL&&bt->data!=x){
stack[++top].t=bt;//入栈
stack[top].tag=0;//第一次遍历该位置
bt=bt->lchild;
}
if(bt->data=x){
for(int i=0;i<=top;i++)
printf("%d",stack[i].t->data);
}
while(top!=-1&&stack[top].tag=1)
top--;
if(top!=-1){
stack[top].tag=1;
bt=stack[top].t->rchild;
}
}
}
27.找到p和q最近公共祖先结点r
//类比后序遍历的非递归实现,这里主要是将后序遍历的出口的条件改正了
typedef struct{
BTNode *t;
int tag;
}Stack;
Stack s[],s1[];
BTNode fun(BT* Root,BT*p,BT*q){
int top=-1;
BTNode *bt=Root;
while(bt!=NULL||top!=0){
while(bt!=NULL){
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild;
}
while(top!=0&&s[top].tag==1){
if(s[top].t==p){
for(int i=0;i<=top;i++)
s1[i]=s[i];
int top1=top;
}
if(s[top].t==q)//如果找到等于q的值
for(i=top;i>0;i--)//s的栈往后退寻找
for(j=top1;j>0;j--)//s1的栈也往后退寻找
if(s1[j].t==s[i].t)//如果已经找到又相同的结点
return s[i].t//那么就返回该节点,查找成功
top--
}
if(top!=-1){
s[top].tag=1;
bt=s[top].t->rchild;
}
}
return NULL;
}
28.自下而上从右到左的层次遍历
void fun(BTNode *p){
Stack s;
Queue Q;
if(p!=NULL){
InitStack(s);
InitQueue(Q);
EnQueue(Q,p);
while(IsEmpty(Q)==false){
DeQueue(Q,p);
push(s,p);
if(p->lchild)
EnQueue(Q,p->lchild);
if(p->rchild)
EnQueue(Q,p->rchild);
}
while(IsEmpty(s)==false){
pop(s,p);
visit(p);
}
}
}
29.二叉树是否为完全二叉树
bool fun(BTNode *p){
Queue Q;
InitQueue(Q);
if(p==NULL)
return true;
EnQueue(Q,p);
while(!IsEmpty(Q)){
DeQueue(Q,p);
if(p!=NULL){
EnQueue(Q,p->lchild);
EnQueue(Q,p->rchild);
}
else while(!IsEmpty(Q)){
DeQueue(Q,p);
if(p!=NULL)
return false;
}
}
}
30.对树中每个元素为x的结点,删除以它为根的子树,并释放空间
//首先查找为x的结点
void Search(BTNode *bt,int x){
BTNode *Q[];
if(bt!=NULL){
//如果最初的根节点就是x的话
if(bt->data==x){
delete(bt);
}
Queue Q;
//存储遍历各结点
InitQueue(Q);
EnQueue(Q,p);
while(!IsEmpty(Q)){
DeQueue(Q,p);
if(p->lchild!=NULL)
if(p->lchild->data==x){
delete(p->lchild);
p->lchild=NULL;
}
else
EnQueue(Q,p->lchild);
if(p->rchild!=NULL)
if(p->rchild->data==x){
delete(p->rchild);
p->rchild=NULL;
}
else
EnQueue(Q,p->rchild);
}
}
}
//再删除以为根节点的子树的方法
void delete(BTNode *bt){
if(bt!=NULL){
delete(bt->lchild);
delete(bt->rchild);
free(bt);
}
}
31.判断是否为二叉排序树
Bool isBST(BTNode *bt){
if(bt==NULL)
return true;
if(bt->lchild==NULL&&bt->rchild==NULL)
return true;
if(bt->lchild->data<bt->data&&bt->data<bt->rchild->data)
return isBST(bt->lchild)&&isBST(bt->rchild);
}
32.数组顺序构造一棵二叉树
node* create(Type x) { //创建一个结点
node* n = new node;
n->data = x;
n->lchild = n->rchild = NULL;
return n;
}
//通过 arr[i] 元素创建 root 结点,注意是 root 地址的引用
node* insertLeverOrder(Type arr[], node* &root, int i, int n) {
if(i < n) {
node* temp = create(arr[i]);
root = temp;
root->lchild = insertLeverOrder(arr, root->lchild, 2 * i, n);
root->rchild = insertLeverOrder(arr, root->rchild, 2 * i + 1, n);
}
return root;
}
33.求编号i和j的最近公共祖先结点的值
int FindParent(BiTree T,int i,int j){
if(T[i]!='#'&&T[j]!='#'){
while(i!=j){
if(i>j)
i=i/2;
else
j=j/2;
}
return T[i];
}
}