注意 ! 这里主要是帮助博主自己复习hhhhh
目录
判断是否是完全二叉树
根据提示借助层序遍历,针对几种情况进行判断。
//判断是否是完全二叉树
bool BiTree::isWanquan(BiNode* bt){
BiNode* p;
queue<BiNode*> Q;
Q.push(bt);
int a1=0,a2=0; //a1是第二种情况,a2是第三种情况
while(!Q.empty()){
p=Q.front();
Q.pop();
if(a1==1||a2==1) //需要判断
if(!(p->lchild==NULL&&p->rchild==NULL)){
return false;
}
if(p->rchild!=NULL&&p->lchild==NULL){
return false;
}
if(p->lchild!=NULL&&p->rchild==NULL) a1=1; //有左孩子无右孩子:需要判断后续是否全为叶子节点
if(p->lchild==NULL&&p->rchild==NULL) a2=1; //是叶子节点,如上
if(p->lchild!=NULL) Q.push(p->lchild);
if(p->rchild!=NULL) Q.push(p->rchild);
}
return true;
}
删除一个节点
能A的代码是从父节点判断左右孩子是否匹配,这里就存在根节点没有父节点这个需要特判的情况了
我比较有问题的是,为什么不能直接判断当前节点是否匹配,然后删除呢??
//删除结点
void BiTree::del(BiNode* bt,char ch){
// if(root==NULL) return;
// if(root->data==ch){
// root=NULL;
// return;
// }
// if(bt->lchild!=NULL){
// if(bt->lchild->data==ch) bt->lchild=NULL;
// else del(bt->lchild,ch);
// }
// if(bt->rchild!=NULL){
// if(bt->rchild->data==ch) bt->rchild=NULL;
// else del(bt->rchild,ch);
// }
// return;
//我不理解为什么这里不行?
if(bt==NULL) return;
if(bt->data==ch) bt==NULL;
else{
del(bt->lchild,ch);
del(bt->rchild,ch);
}
return;
}
层序存储输出前序
下标从1开始
左:2*i
右:2*i+1
下标从0开始
左:2*i+1
右:2*i+2
下标超出范围的时候返回。
//使用数组对二叉树进行存储
#include<iostream>
#include<string.h>
using namespace std;
const int N=1e5+10;
char q[N]={0};
int len;
void print(int i){
if(i>len-1) return;
if(q[i]!='^') printf("%c",q[i]);
print(i*2+1); //左边
print(i*2+2); //右边
}
int main(){
scanf("%s",q);
len=strlen(q);
print(0);
}
前序中序推后序
前序:根->左->右
中序:左->根->右
后序:左->右->根
一些说明:
1.基本思路:在中序中找到根节点,左边即为根节点的左子树,右边为右子树。先递归左子树再递归右子树,最后打印该根节点。
存储根节点,创建左子树,创建右子树。
2.使用了string类里面的find()和substr()函数
find():找到括号内的第一次出现参数的位置并返回其下标
substr():截取数组,左闭右开
这段代码使用链表的方式创建了二叉树,再对其进行后序遍历
#include<iostream>
#include<string>
using namespace std;
typedef struct Tree{
char data;
struct Tree *lchild,*rchild;
}Node,*BTree;
void build(BTree &T,string str1,string str2){
if(str1.size()==0&&str2.size()==0) T=NULL;
else{
T=new Node;
T->data=str1[0];
int pos=str2.find(str1[0]);
string str_L1=str1.substr(1,pos);
string str_R1=str1.substr(pos+1,str1.length());
string str_L2=str2.substr(0,pos);
string str_R2=str2.substr(pos+1,str2.length());
build(T->lchild,str_L1,str_L2);
build(T->rchild,str_R1,str_R2);
}
return;
}
void postPrint(BTree T){
if(T==NULL) return;
postPrint(T->lchild);
postPrint(T->rchild);
cout<<T->data;
}
int main(){
BTree T;
string str1,str2;
cin>>str1;
cin>>str2;
build(T,str1,str2);
cout<<"后序遍历:";
postPrint(T);
return 0;
}
这里还有一种为了快速应考的代码
思路是上面那个删除线部分
#include<iostream>
#include<string>
string a,b;//a是前序,b是中序
void build(int l1,int r1,int l2,int r2){
for(int i=0;i<=r2;i++){
if(a[l1]==b[i]){
build(l1+1,r1,l2,i-1);
build(l1+i-l2+1,r1,i+1,r2);
cout<<a[i];
}
}
return;
}
int main(){
cin>>a>>b;
int r=a.size()-1;
build(0,r,0,r);
}
求二叉树的镜像
#include<iostream>
#include<stdio.h>
#include<string.h>
const int MAX=1000;
using namespace std;
struct BiNode
{
char data;//数据域
BiNode *lchild, *rchild;//左右儿子指针
};
class BiTree {
private:
BiNode *root;
public:
BiNode* getRoot(){return root;}
BiTree(){root=creat(root);}
BiNode* creat(BiNode* bt);
void trans(BiNode* bt);
void prePrint(BiNode* bt);
};
BiNode *BiTree::creat(BiNode* bt){
char ch;
cin>>ch;
if(ch=='#') bt=NULL;
else{
bt=new BiNode;
bt->data=ch;
bt->lchild=creat(bt->lchild);
bt->rchild=creat(bt->rchild);
}
return bt;
}
void BiTree::trans(BiNode* bt){
if(bt==NULL) return;
if(bt->lchild!=NULL&&bt->rchild!=NULL){
BiNode* p=bt->lchild;
bt->lchild=bt->rchild;
bt->rchild=p;
}
if(bt->lchild!=NULL) trans(bt->lchild);
if(bt->rchild!=NULL) trans(bt->rchild);
return;
}
void BiTree::prePrint(BiNode* bt){
if(bt==NULL) return;
cout<<bt->data;
prePrint(bt->lchild);
prePrint(bt->rchild);
}
int main(){
BiTree tree;
tree.trans(tree.getRoot());
cout<<"镜像后二叉树的前序遍历序列是:";
tree.prePrint(tree.getRoot());
return 0;
}
将左右孩子交换
求第K层结点数
两种方法:
递归:
定义一个全局变量初值为0.
传参k,每次访问子树(下一层)时就在传参时将k-1,当k=1时,就说明在该节点在第k层,num++
(所以每次访问之前都要判断左右孩子是否为空,为空就不能访问)
void BiTree::getNode_Num1(BiNode* bt,int k){
if(k==1){
num++;
return;
}
else{
if(bt->lchild!=NULL) getNode_Num1(bt->lchild,k-1);
if(bt->rchild!=NULL) getNode_Num1(bt->rchild,k-1);
return;
}
}
迭代:
又是利用层序遍历,记录该层的总个数,将该层访问完(边访问边入队)。每次访问完一层后,层数++,若当前层数等于所求层数,就返回记录的该层总个数
int GetKthLevelNodesTotal( BTreeNode_t *pRoot, unsigned int KthLevel ){
if( pRoot == NULL )
return 0;
queue <BTreeNode_t *> que;
que.push( pRoot );
int curLevelNodesTotal = 0;
int curLevel = 0;
while( !que.empty() ){
++curLevel;//当前层数
curLevelNodesTotal = que.size();
if( curLevel == KthLevel )//如果层数等于给定层数
break;
int cntNode = 0;
while( cntNode < curLevelNodesTotal){//将下一层节点入队
++cntNode;
pRoot = que.front();
que.pop();
if( pRoot->m_pLeft != NULL )
que.push(pRoot->m_pLeft);
if( pRoot->m_pRight != NULL )
que.push( pRoot->m_pRight);
}
}
while ( !que.empty() )
que.pop();
if( curLevel == KthLevel )
return curLevelNodesTotal;
return 0; //如果KthLevel大于树的深度
}
总的代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
const int MAX=1000;
using namespace std;
int num=0;
struct BiNode
{
char data;//数据域
BiNode *lchild, *rchild;//左右儿子指针
};
class BiTree {
private:
BiNode *root;
public:
BiNode* getRoot(){return root;}
BiTree(){root=creat(root);}
BiNode* creat(BiNode* bt);
void trans(BiNode* bt);
void prePrint(BiNode* bt);
void getNode_Num1(BiNode* bt,int k);
};
BiNode *BiTree::creat(BiNode* bt){
char ch;
cin>>ch;
if(ch=='#') bt=NULL;
else{
bt=new BiNode;
bt->data=ch;
bt->lchild=creat(bt->lchild);
bt->rchild=creat(bt->rchild);
}
return bt;
}
void BiTree::trans(BiNode* bt){
if(bt==NULL) return;
if(bt->lchild!=NULL&&bt->rchild!=NULL){
BiNode* p=bt->lchild;
bt->lchild=bt->rchild;
bt->rchild=p;
}
if(bt->lchild!=NULL) trans(bt->lchild);
if(bt->rchild!=NULL) trans(bt->rchild);
return;
}
void BiTree::prePrint(BiNode* bt){
if(bt==NULL) return;
cout<<bt->data;
prePrint(bt->lchild);
prePrint(bt->rchild);
}
void BiTree::getNode_Num1(BiNode* bt,int k){
if(k==1){
num++;
return;
}
else{
if(bt->lchild!=NULL) getNode_Num1(bt->lchild,k-1);
if(bt->rchild!=NULL) getNode_Num1(bt->rchild,k-1);
return;
}
}
int main(){
BiTree tree;
int k;
cin>>k;
tree.getNode_Num1(tree.getRoot(),k);
cout<<num;
// tree.trans(tree.getRoot());
// cout<<"镜像后二叉树的前序遍历序列是:";
// tree.prePrint(tree.getRoot());
return 0;
}
int GetKthLevelNodesTotal( BTreeNode_t *pRoot, unsigned int KthLevel ){
if( pRoot == NULL )
return 0;
queue <BTreeNode_t *> que;
que.push( pRoot );
int curLevelNodesTotal = 0;
int curLevel = 0;
while( !que.empty() ){
++curLevel;//当前层数
curLevelNodesTotal = que.size();
if( curLevel == KthLevel )//如果层数等于给定层数
break;
int cntNode = 0;
while( cntNode < curLevelNodesTotal){//将下一层节点入队
++cntNode;
pRoot = que.front();
que.pop();
if( pRoot->m_pLeft != NULL )
que.push(pRoot->m_pLeft);
if( pRoot->m_pRight != NULL )
que.push( pRoot->m_pRight);
}
}
while ( !que.empty() )
que.pop();
if( curLevel == KthLevel )
return curLevelNodesTotal;
return 0; //如果KthLevel大于树的深度
}
完全二叉树:后序推层序遍历
使用数组模拟二叉树,根据完全二叉树的特点,
已知任意一种遍历,可以唯一的确定一颗完全二叉树
#include<iostream>
using namespace std;
const int N=1e5+10;
int n,m;
char postorder[N],tree[N];
int ind=1;
void gettree(int x){
if(x>n) return;
else{
gettree(x*2);
gettree(x*2+1);
tree[x]=postorder[ind++];
}
return;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>postorder[i];
gettree(1);
for(int i=1;i<=n;i++) printf("%c",tree[i]);
return 0;
}