术语:
节点深度:对任意节点x,x节点的深度表示为根节点到x节点的路径长度。所以根节点深度为0,第二层节点深度为1,以此类推
节点高度:对任意节点x,叶子节点到x节点的路径长度就是节点x的高度
树的深度:一棵树中节点的最大深度就是树的深度,也称为高度
父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点
子节点:一个节点含有的子树的根节点称为该节点的子节点
节点的层次:从根节点开始,根节点为第一层,根的子节点为第二层,以此类推
兄弟节点:拥有共同父节点的节点互称为兄弟节点
度:节点的子树数目就是节点的度
叶子节点:度为零的节点就是叶子节点
祖先:对任意节点x,从根节点到节点x的所有节点都是x的祖先(节点x也是自己的祖先)
后代:对任意节点x,从节点x到叶子节点的所有节点都是x的后代(节点x也是自己的后代)
森林:m颗互不相交的树构成的集合就是森林
---------------------
作者:zeling1005
来源:CSDN
原文:https://blog.csdn.net/u014532217/article/details/79118023
版权声明:本文为博主原创文章,转载请附上博文链接!
树、二叉树、森林的转换
https://blog.csdn.net/jiashuai94/article/details/80760041
二叉树的遍历
#include<bits/stdc++.h>
using namespace std;
typedef int ElemType;
typedef struct tree{
ElemType elem;
int time;
tree *left,*right;
};
tree* creat(){
tree *t;
int x;
cin>>x;
if(!x) return NULL;
else{
t=(tree*)malloc(sizeof(tree));
t->elem=x;
t->left=creat();
t->right=creat();
}
return t;
}
void preorder(tree* root){//递归先序
if(root!=NULL){
cout<<root->elem<<" ";
preorder(root->left);
preorder(root->right);
}
}
void inorder(tree* root){//递归中序
if(root!=NULL){
inorder(root->left);
cout<<root->elem<<" ";
inorder(root->right);
}
}
void postorder(tree* root){//递归后序
if(root!=NULL){
postorder(root->left);
postorder(root->right);
cout<<root->elem<<" ";
}
}
void preorder2(tree *root){//非递归先序
stack<tree*> st;
while(st.size()>0||root!=NULL){
while(root!=NULL){
st.push(root);
cout<<root->elem<<" ";
root=root->left;
}
if(st.size()>0){
root=st.top();
st.pop();
root=root->right;
}
}
cout<<endl;
}
void inorder2(tree *root){//非递归中序
stack<tree*> st;
while(st.size()>0||root!=NULL){
while(root!=NULL){//一直深入左子树
st.push(root);
root=root->left;
}
if(st.size()>0){//此时在最左
root=st.top();//返回上一结点
st.pop();
cout<<root->elem<<" ";
root=root->right;//深入右子树
}
}
cout<<endl;
}
void postorder2(tree *root){//非递归后序
stack<tree*> st;
tree *p;
while(root!=NULL||st.size()>0){
while(root!=NULL){
root->time++;
st.push(root);//第一次入栈,不用访问
root=root->left;
}
if(st.size()){
root=st.top();
st.pop();
if(root->time==1){
root->time++;
st.push(root);//第二次入栈(即遇到),不用访问
root=root->right;
}
else{
cout<<root->elem<<" ";
root=NULL;//root结点已经是第三次遇见,那么左右子树也已经访问过,可置NULL,也可去掉
}
}
}
cout<<endl;
}
//本质和2一样
void preorder3(tree *root){
stack<tree*> st;
if(!root) return;
st.push(root);
while(!st.empty()){
tree *t=st.top();
st.pop();
printf("%d ",t->elem);
if(t->right) st.push(t->right);
if(t->left) st.push(t->left);
}
}
void inorder3(tree *root){
if(!root) return;
stack<tree*> st;
tree *p=root;
while(!st.empty()||p){
while(p){
st.push(p);
p=p->left;
}
p=st.top();
st.pop();
printf("%d ",p->elem);
//如果有右孩子赋值为右孩子
if(p->right){
p=p->right;
}
//否则赋值为NULL,下一次循环跳过while,找到新结点的右孩子
else p=NULL;
}
}
void postorder3(tree* root){
//两个栈
/*
stack<tree*> st1,st2;
st1.push(root);
while(!st1.empty()){
tree *cur = st1.top();
st1.pop();
st2.push(cur);
if(cur->left) st1.push(cur->left);
if(cur->right) st1.push(cur->right);
}
while(!st2.empty()){
cout<<st2.top()->elem<<" ";
st2.pop();
}
*/
//一个栈
/**/
stack<tree*> st;
st.push(root);
tree *c= root;
while(!st.empty()){
tree *cur=st.top();
if(cur->left && cur->left!=c && cur->right!=c){
st.push(cur->left);
}
else if(cur->right && cur->right!=c){
st.push(cur->right);
}
else{
st.pop();
c=cur;
cout<<cur->elem<<" ";
}
}
}
int NumOfNode(tree *root){
if(root==NULL) return 0;
return 1+NumOfNode(root->left)+NumOfNode(root->right);
}
int NumOfLeaf(tree *root){
if(root!=NULL){
if(root->left==NULL && root->right==NULL)
return 1;
return NumOfLeaf(root->left)+NumOfLeaf(root->right);
}
}
int DepthOfTree(tree *root){//求树深
if(root==NULL) return 0;
int dl=DepthOfTree(root->left);
int dr=DepthOfTree(root->right);
return 1+max(dl,dr);
}
int main(){
tree *root;
root=creat();
postorder(root);
cout<<endl;
postorder3(root);
cout<<endl;
// postorder(root);
// cout<<endl;
// postorder2(root);
// cout<<endl;
// inorder(root);
// cout<<endl;
// cout<<"结点数:"<<NumOfNode(root)<<endl;
// cout<<"叶结点数:"<<NumOfLeaf(root)<<endl;
// cout<<"树深:"<<DepthOfTree(root)<<endl;
return 0;
}
//11 12 14 0 16 0 0 0 12 15 0 0 0
非递归写法详解:
https://blog.csdn.net/woshinannan741/article/details/52825163
线索二叉树
二叉树每个结点都有指针left和right,当子树为空时它们是空链域,为了避免空间浪费,若结点的左子树为空,则指向遍历序列的前驱,若结点的右子树为空,则指向遍历序列的后继
https://blog.csdn.net/u014492609/article/details/40477795
哈弗曼树
https://blog.csdn.net/luoluozlb/article/details/52122874
#include<bits/stdc++.h>
using namespace std;
typedef int ElemType;
const int MAX=1e5+5;
typedef struct HuffTree{
int weight;//权值
int lch,rch;
int tag;
bool operator<(const HuffTree& temp) const{
return this->weight<temp.weight;
}
}HuffTree;
int hufftree(HuffTree *&ht){
int n;//叶子结点的个数
cin>>n;
ht = new HuffTree[2*n];
for(int i=1;i<=n;i++){
cin>>ht[i].weight;
ht[i].lch=ht[i].rch=ht[i].tag=0;
}
int i=0;
while(i<n-1){//合并n-1次
int x1=0,m1=0x3f3f3f3f;//m1是最小值单元,x1为下标
int x2=0,m2=0x3f3f3f3f;//m2是次小值单元,x2为下标
for(int j=1;j<=n+i;j++){
if(ht[j].weight<m1&&!ht[j].tag){
m2=m1;
x2=x1;
m1=ht[j].weight;
x1=j;
}
else if(ht[j].weight<m2&&!ht[j].tag){
m2=ht[j].weight;
x2=j;
}
}
i++;
ht[x1].tag=ht[x2].tag=1;
ht[n+i].weight=ht[x1].weight+ht[x2].weight;
ht[n+i].tag=0;
ht[n+i].lch=x1;
ht[n+i].rch=x2;
}
return 2*n-1;
}
int hufftree_WPL(HuffTree *ht,int i,int depth){
if(!ht[i].lch&&!ht[i].rch){
return ht[i].weight*depth;
}
else{
return hufftree_WPL(ht,ht[i].lch,depth+1)+hufftree_WPL(ht,ht[i].rch,depth+1);
}
}
int main(){
int n;
HuffTree *ht;
n=hufftree(ht);
printf(" tag lch weight rch\n");
for(int i=1;i<=n;i++){
printf("%d %d %d %d %d\n",i,ht[i].tag,ht[i].lch,ht[i].weight,ht[i].rch);
}
cout<<hufftree_WPL(ht,n,0);
return 0;
}
AVL深入解读
https://blog.csdn.net/qpzkobe/article/details/81611486
https://blog.csdn.net/Love_Irelia97/article/details/82895991
#include <bits/stdc++.h>
#define rep1(i,s,e,c) for(int i=s;i<e;i=i+c)
#define rep2(i,s,e,c) for(int i=s;i<=e;i=i+c)
#define rep3(i,e,s,c) for(int i=e;i>=s;i=i-c)
using namespace std;
typedef long long ll;
typedef int ElemType;
const int MAXSIZE=10005;
struct AVLtree{
ElemType elem;
int bf,height;//bf=左子树高度减去右子树高度
AVLtree *left,*right;
//构造函数
AVLtree(ElemType x):elem(x),left(NULL),right(NULL),bf(0),height(0){}
};
int getHeight(AVLtree *t){
return (t==NULL?-1:t->height);
}
void reHeight_bf(AVLtree *root){
int hl=getHeight(root->left);
int hr=getHeight(root->right);
//更新树高和平衡因子
root->height=max(hl,hr)+1;
root->bf=hl-hr;
}
void LL_Rotate(AVLtree *&root){//LL表示插入到左子树的左子树,需要右旋
AVLtree *t = root;
AVLtree *L = root->left;//root的左子树
AVLtree *LR = L->right;//root的左子树的右子树
//开始右旋
L->right=t;
t->left=LR;
root=L;
//旋转后结点位置变化,更新树高
reHeight_bf(root->right);
reHeight_bf(root);
}
void RR_Rotate(AVLtree *&root){//RR表示插入到右子树的右子树,需要左旋
AVLtree *t = root;
AVLtree *R = root->right;//root的右子树
AVLtree *RL = R->left;//root的右子树的左子树
//开始左旋
R->left=t;
t->right=RL;
root=R;
//旋转后结点位置变化,更新树高
reHeight_bf(root->left);//或者t
reHeight_bf(root);
}
void LR_Rotate(AVLtree *&root){
RR_Rotate(root->left);//先对root的左子树根结点左旋
LL_Rotate(root);//再对root结点右旋
}
void RL_Rotate(AVLtree *&root){
LL_Rotate(root->right);
RR_Rotate(root);
}
bool insertElem(AVLtree *&root,ElemType elem){
if(root==NULL){
root = new AVLtree(elem);
return true;
}
//AVL树满足BST性质,不允许有相同的值存在
if(elem==root->elem){
return false;
}
else if(elem<root->elem){
insertElem(root->left,elem);
reHeight_bf(root);//插入后更新平衡因子bf
if(root->bf>1){
//结点插入到左子树的左结点,LL
if(elem<root->left->elem){
LL_Rotate(root);
}
//否则插入到左子树的右结点 ,LR
else{
LR_Rotate(root);
}
}
}
else{
insertElem(root->right,elem);
reHeight_bf(root);
if(root->bf<-1){
//结点插入到右子树的右结点,RR
if(elem>root->right->elem){
RR_Rotate(root);
}
//否认则插入到右子树的左结点,RL
else{
RL_Rotate(root);
}
}
}
return true;
}
//中序遍历下的前驱
AVLtree* find_LeftMax(AVLtree *root){
AVLtree *t=root->left;//左子树中找最右下结点
while(t->right!=NULL){
t=t->right;
}
return t;
}
//中序遍历下的后继
AVLtree* find_RightMin(AVLtree *root){
AVLtree *t=root->right;//右子树中找最左下结点
while(t->left!=NULL){
t=t->left;
}
return t;
}
bool deleteElem(AVLtree *&root,const int x){
if(root==NULL) return false;
//查找到要删除的结点
if(x==root->elem){
AVLtree *t=root;
//左右子树都存在
if(root->left!=NULL && root->right!=NULL){
//若删除结点的左子树高度>右子树高度
//找到该结点的前驱
if(getHeight(root->left)>getHeight(root->right)){
t=find_LeftMax(root);
root->elem=t->elem;
deleteElem(root->left,t->elem);
}
//否则找该结点的后继
else{
t=find_RightMin(root);
root->elem=t->elem;
deleteElem(root->right,t->elem);
}
}
else{
root=(root->left)?root->left:root->right;
delete t;
}
}
//左子树递归
else if(x<root->elem){
//未找到删除结点,直接返回
if(!deleteElem(root->left,x)){
return false;
}
reHeight_bf(root);
//删除左子树结点后失去平衡
if(root->bf<-1){
AVLtree *t=root->right;
//右子树的左子树比右子树的右子树高
//相当于在右子树的左子树插入结点
if(getHeight(t->left)>getHeight(t->right)){
RL_Rotate(root);
}
//否则相当在右子树的右子树插入结点,RR
else{
RR_Rotate(root);
}
}
}
//右子树递归
else{
//未找到删除结点,直接返回
if(!deleteElem(root->right,x)){
return false;
}
reHeight_bf(root);
//删除右子树结点后失去平衡
if(root->bf>1){
AVLtree *t=root->left;
//左子树的左子树比左子树的右子树高
//相当于在左子树的左子树插入结点,LL
if(getHeight(t->left)>getHeight(t->right)){
LL_Rotate(root);
}
else{
LR_Rotate(root);
}
}
}
return true;
}
void inorder(AVLtree *root){//非递归中序
stack<AVLtree*> st;
while(st.size()>0||root!=NULL){
while(root!=NULL){
st.push(root);
root=root->left;
}
if(st.size()>0){
root=st.top();
st.pop();
cout<<root->elem<<" ";
root=root->right;
}
}
}
void inorder2(AVLtree *root){
if(root!=NULL){
if(root->left!=NULL)
inorder2(root->left);
cout<<root->elem<<" ";
if(root->right!=NULL)
inorder2(root->right);
}
}
void preorder(AVLtree *root)
{
if(root!=NULL){
cout<<root->elem<<" ";
if(root->left!=NULL)
preorder(root->left);
if(root->right!=NULL)
preorder(root->right);
}
}
void postorder(AVLtree *root)
{
if(root!=NULL){
if(root->left!=NULL)
postorder(root->left);
if(root->right!=NULL)
postorder(root->right);
cout<<root->elem<<" ";
}
}
int main()
{
AVLtree *root=NULL;
ElemType data_arr[]={1,21,2,205,13,50,6};
for(int i=0;i<7;i++){//根据插入元素操作得到AVL树
insertElem(root,data_arr[i]);
}
inorder2(root);
cout<<endl;
preorder(root);
cout<<endl;
return 0;
}
无视下面的代码,只是我又敲了一遍练手
#include <bits/stdc++.h>
#define rep1(i,s,e,c) for(int i=s;i<e;i=i+c)
#define rep2(i,s,e,c) for(int i=s;i<=e;i=i+c)
#define rep3(i,e,s,c) for(int i=e;i>=s;i=i-c)
using namespace std;
typedef long long ll;
const int MAX=2e5+1;
const int MOD=1e9+7;
typedef int ElemType;
struct Node{
ElemType elem;
int bf,height;
Node *left,*right;
Node(ElemType x):elem(x),bf(0),height(0),left(NULL),right(NULL) {}
};
typedef Node *AVLtree;
int getHeight(AVLtree p){
return p==NULL?-1:p->height;
}
void reHeight_bf(AVLtree p){
int hl=getHeight(p->left);
int hr=getHeight(p->right);
p->height=max(hl,hr)+1;
p->bf=hl-hr;
}
void LL_Rotate(AVLtree &p){
AVLtree L=p->left;
AVLtree LR=L->right;
p->left=LR;
L->right=p;
p=L;
reHeight_bf(p->right);
reHeight_bf(p);
}
void RR_Rotate(AVLtree &p){
AVLtree R=p->right;
AVLtree RL=R->left;
p->right=RL;
R->left=p;
p=R;
reHeight_bf(p->left);
reHeight_bf(p);
}
void LR_Rotate(AVLtree &p){
RR_Rotate(p->left);
LL_Rotate(p);
}
void RL_Rotate(AVLtree &p){
LL_Rotate(p->right);
RR_Rotate(p);
}
bool insertElem(AVLtree &p,ElemType x){
if(p==NULL){
p=new Node(x);
return true;
}
if(x==p->elem){
return false;
}
if(x<p->elem){
insertElem(p->left,x);
reHeight_bf(p);
if(p->bf>1){
if(x<p->left->elem){
LL_Rotate(p);
}
else{
LR_Rotate(p);
}
}
}
else{
insertElem(p->right,x);
reHeight_bf(p);
if(p->bf<-1){
if(x>p->right->elem){
RR_Rotate(p);
}
else RL_Rotate(p);
}
}
return true;
}
AVLtree find_LeftMax(AVLtree p){
AVLtree t=p->left;
while(t->right)
t=t->right;
return t;
}
AVLtree find_RightMin(AVLtree p){
AVLtree t=p->right;
while(t->left)
t=t->left;
return t;
}
bool deleteElem(AVLtree &p,int x){
if(p==NULL) return false;
if(x==p->elem){
AVLtree t=p;
if(p->left && p->right){
if(getHeight(p->left)>getHeight(p->right)){
t=find_LeftMax(p);
p->elem=t->elem;
deleteElem(p->left,p->elem);
}
else{
t=find_RightMin(p);
p->elem=t->elem;
deleteElem(p->right,p->elem);
}
}
else{
p=p->left?p->left:p->right;
delete t;
}
}
else if(x<p->elem){
if(!deleteElem(p->left,x)){
return false;
}
reHeight_bf(p);
if(p->bf<-1){
AVLtree t=p->right;
if(getHeight(t->left)>getHeight(t->right)){
RL_Rotate(p);
}
else{
RR_Rotate(p);
}
}
}
else{
if(!deleteElem(p->right,x)){
return false;
}
reHeight_bf(p);
if(p->bf>1){
AVLtree t=p->left;
if(getHeight(t->left)>getHeight(t->right)){
LL_Rotate(p);
}
else{
LR_Rotate(p);
}
}
}
return true;
}
void preorder(AVLtree p){
stack<AVLtree> st;
while(!st.empty()||p){
while(p){
st.push(p);
cout<<p->elem<<" ";
p=p->left;
}
if(!st.empty()){
p=st.top();
st.pop();
p=p->right;
}
}
cout<<endl;
}
void inorder(AVLtree p){
stack<AVLtree> st;
while(!st.empty()||p){
while(p){
st.push(p);
p=p->left;
}
if(!st.empty()){
p=st.top();
st.pop();
cout<<p->elem<<" ";
p=p->right;
}
}
cout<<endl;
}
int main()
{
AVLtree root=NULL;//root一定要初始化NULL,不然insert的时候会出事
ElemType data_arr[]={1,21,2,205,13,50,6};
for(int i=0;i<7;i++){//根据插入元素操作得到AVL树
insertElem(root,data_arr[i]);
}
deleteElem(root,205);
preorder(root);
inorder(root);
return 0;
}
指针和引用的区别
https://blog.csdn.net/superwangxinrui/article/details/80565594
*&和&*(去搜),引用的指针和指针的引用,离变量越近越先解读,如上述代码中的AVLtree *&root,首先&表示引用,然后是AVLtree*类型的变量。