文章目录
(一)简介
树的层次:根节点为第一层
结点的度:结点拥有的子树
叶子结点:度为0
满二叉树:每一层的结点都为当层结点的最大数
完全二叉树:除最后一层 每一层的结点都为当层结点的最大数 最后一层结点在最左边连续
(二)建树步骤
strcut node
{
typename data ; //数据域
node* lchild;//指向左子树根节点的指针
node* rchild; //指向右子树根节点的指针
}
建树前根结点为空
node* root = NULL;
返回一个新节点
node* newNode(int v)
{
node* Node = new node;
Node -> data = v;
Node -> lchild = Node -> rhild = NULL;//左右儿子初始化
return Node;
}
查找一个数并作修改
void search(node* root,int x,int newdata)
{
if(root == NULL)
return;
if(root -> data == x)
root -> data = newdata;
search(root -> lchild, x , newdata);
search(root -> rchild, x , newdata);
}
void insert(node* &root,int x)
{
if(root == NULL)
{
root = newNode();
return ;
}
if
{
insert(root -> lchild , x);
}
else
{
insert(root -> rchild, x);
}
}
node* create(int data[],int n)
{
node* root = NULL;
for(int i =0 ; i < n;i++)
{
insert(root , data[i]);
}
return root;
}
对于完全二叉树的存储 用1-n的下标将二叉树从左至右从上至下编号存入数组中 其顺序正好是层序遍历
(三)二叉树遍历
(1)先序遍历
void preorder(node* root)
{
if(root == NULL)
return;
printf("%d",root -> data);
preorder(root -> lchild);
preorder(root -> rchild);
}
(2) 中序遍历
void inorder(node* root)
{
if(root == NULL)
return;
preorder(root -> lchild);
printf("%d",root -> data);
preorder(root -> rchild);
}
(3)后序遍历
void postorder(node* root)
{
if(root == NULL)
return;
preorder(root -> lchild);
preorder(root -> rchild);
printf("%d",root -> data);
}
(4)层序遍历
void Layerorder(node* root)
{
queue<node*> q;
q.push(root);
while(!q.empty())
{
node* now = q.front();
q.pop();
printf("%d",now -> data);
if(now -> lchild)q.push(now -> lchild);
if(now -> rchild)q.push(now -> rchild);
}
}
(5)记录层数的层序遍历
struct node
{
int data;
int layer;
node* lchild;
node* rchild;
};
void Layerorder(node* root)
{
queue<node*> q;
q.push(root);
root -> layer = 1;
while(!q.empty())
{
node* now = q.front();
q.pop();
printf("%d",now -> data);
if(now -> lchild)
{
now -> lchild -> layer = now -> layer + 1;
q.push(now -> lchild);
}
if(now -> rchild)
{
now -> rchild -> layer = now -> layer + 1;
q.push(now -> rchild);
}
}
}
(四)还原二叉树
(1)先中还原
node* create(int prel,int prer,int inl,int inr)
{
if(prel > prer)
return NULL;//先序长度小于0
node* root = new node;
int k;
for(k = inl ; k <= inr ; k++)
{
if(in[k] == pre[prel])
break
}//在中序中寻找与先序相同的结点
//k点之前的点即为左子树结点个数
int numleft = k - inl;
//返回左子树的区间
root -> lchild =create(prel + 1, prel + numleft ,inl , k -1);
//返回右子树的区间
root -> rchild = create(prel + numleft +1 ,prer , k + 1 , inr);
return root;
}
(2)中后还原
node* create(int postl,int postr,int inl,int inr)
{
if(postl > postr)
return NULL;
node* root = new node;
root -> data = post[postr];
int k;
for( k = inl ; k <= inr ;k ++)
if(post[postr] == in[k])
break;
int numleft = k - inl;
//区间长度要为numleft
root -> lchild = create(postl,postl + numleft-1,inl,k -1 );
root -> rchild = create(postl + numleft , potr - 1 , k + 1, inr);
}
(三)中层还原
Node *rebuildTree(int ll, int lr, int il, int ir) {
if(il > ir) return NULL;
Node *root = NULL;
int i, j;
for(i = ll; i<=lr; i++) {
if(m[lev[i]] == 1) continue;
bool flag = false;
for(j = il; j<=ir; j++) {
if(lev[i] == in[j]) {
flag = true;
break;
}
}
if(flag) {
m[lev[i]] = 1;
root = new Node(lev[i]);
root->left = rebuildTree(ll, lr, il, j-1);
root->right = rebuildTree(ll, lr, j+1, ir);
break;
}
}
return root;
}
(五)树的静态写法
struct node
{
typename data;//数据域
int child[maxn];
}NODE[maxn] //数组下标代替地址;
struct node
{
typename data;
vector<int> child;
}NODE[maxn];
(六)静态树遍历
(1)先根遍历
void preorder(int root)
{
printf("%d",NODE[root].data);
for(int i =0 ;i < NODE[root].child.size();i++)
preorder(NODE[root].child[i]);
}
(2)层序遍历
//和动态没多大区别吧
void Layerorder(int root)
{
queue<int> q;
q.push(root);
while(!q.empty())
{
int front = q.front();
printf("%d",NODE[front].data);
q.pop();
for(int i =0 ; i < NODE[front].child.size();i++)
q.push(NODE[front].child[i]);
}
}
(七)还原二叉树题解
(1)1020 Tree Traversals (25分)
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 100;
int post[maxn],inorder[maxn];
struct node
{
int data;
node* left;
node* right;
};
node* rebuild(int postl,int postr,int inl,int inr)
{
if(postl > postr)
return NULL;
node* root = new node;
root -> data = post[postr];
int k;
for(k = inl ; k <= inr ;k++)
if(inorder[k] == post[postr])
break;
int numleft = k - inl;
root -> left = rebuild(postl,postl + numleft -1,inl,k-1);
root -> right = rebuild(postl + numleft ,postr-1, k +1, inr);
return root;
}
void leveloreder(node* root)
{
queue<node*> q;
q.push(root);
int digit =0 ;
while(!q.empty())
{
node* a = q.front();
q.pop();
if(digit)
cout<<" ";
digit++;
cout<<a -> data;
if(a->left)q.push(a->left);
if(a->right)q.push(a ->right);
}
}
int main()
{
int n;
cin>>n;
for(int i =0 ; i< n;i++)
scanf("%d",&post[i]);
for(int i = 0 ; i < n ;i++)
scanf("%d",&inorder[i]);
node * root = rebuild(0,n-1,0,n-1);
leveloreder(root);
}
(2)1086 Tree Traversals Again (25分)
//建完树忘了返回根节点
#include<iostream>
#include<stack>
using namespace std;
const int maxn = 100;
int pre[maxn],inorder[maxn];
stack<int> s;
struct node
{
int data;
node* left;
node* right;
};
node* rebuild(int prel,int prer,int inl,int inr)
{
if(prel > prer)
return NULL;
node* root = new node ;
root -> data = pre[prel];
int k;
for(k = inl;k <= inr ; k++)
if(inorder[k] == pre[prel])
break;
int numleft = k - inl;
root -> left = rebuild(prel+1,prel + numleft , inl,k-1);
root -> right = rebuild(prel + numleft +1 , prer , k+1,inr);
return root;
}
int num = 0;
void BFS(node* root)
{
if(root == NULL)
return;
BFS(root -> left);
BFS(root -> right);
if(num)
cout<<" ";
num++;
cout<<root -> data;
}
int main()
{
int n;
cin>>n;
string stl;
int index1=0,index2 =0 ;
for(int i = 0; i < n *2 ;i++)
{
cin>>stl;
if(stl == "Push")
{
cin>>pre[index1];
s.push(pre[index1 ++]);
}
else if(stl == "Pop")
{
inorder[index2++] = s.top();
s.pop();
}
}
node* root = rebuild(0,n-1,0,n-1);
BFS(root);
}
(3)1102 Invert a Binary Tree (25分)
//给出反转后的二叉树 还原后输出中序 后序
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 1000;
bool vis[maxn];
int n,num =0 ;
struct Node
{
int left,right;
}node[maxn];
int chartonum(char ch)
{
if(isdigit(ch))
{
vis[ch - '0'] = true;
return ch-'0';
}
else
return -1;
}
//找到静态二叉树的根 即没用任何结点指向的
int findroot()
{
for(int i =0 ; i < n ; i++)
if(vis[i] == false)
return i;
}
//通过后序遍历反转二叉树
//原则上先序也可以 不过先序反转后 后面BFS左右调换了
void postorder(int root)
{
if(root == -1)
return;
postorder(node[root].left);
postorder(node[root].right);
swap(node[root].left,node[root].right);
}
void BFS(int root)
{
queue<int> q;
q.push(root);
while(!q.empty())
{
int root = q.front();
q.pop();
if(num)
cout<<" ";
cout<<root;
num ++;
if(node[root].left!= -1)q.push(node[root].left);
if(node[root].right != -1) q.push(node[root].right);
}
}
void in(int root)
{
if(root == -1)
return;
in(node[root].left);
if(num)
cout<<" ";
cout<<root;
num ++;
in(node[root].right);
}
int main()
{
char a,b;
cin>>n;
for(int i =0 ; i < n ;i ++)
{
cin>>a>>b;
node[i].left = chartonum(a);
node[i].right = chartonum(b);
}
int root = findroot();
postorder(root);
BFS(root);
cout<<endl;
num =0 ;
in(root);
}
(八)树的遍历 (DFS)
1090 Highest Price in Supply Chain (25分)
//给出一颗供应树 再给出结点的价格,每向下一层 价格提升%r
//求最高价以及 最高价的结点数
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
const int maxn =100;
vector<int> v[maxn];
double p,r;
int digit =0 ,maxdepth = 0;
void dfs(int root,int index)
{
if(index > maxdepth)
{
digit =1 ;
maxdepth = index;
}
else if(index == maxdepth)
digit ++;
if(v[root].size() ==0)
return;
for(int i =0 ; i< v[root].size();i++)
dfs(v[root][i] , index + 1);
}
int main()
{
int n,root;
cin>>n;
cin>>p>>r;
r = r /100;
for(int i =0 ; i < n ;i ++)
{
int id;
cin>>id;
if(id != -1)
v[id].push_back(i);
else
root = i;
}
dfs(root , 0);
printf("%.2f %d",p * pow(1+r,maxdepth),digit);
}
1079 Total Sales of Supply Chain (25分)
//给出供应树
10 1.80 1.00 //结点个数,货物单价,r
3 2 3 5 // 第i号结点所拥有的结点 及其 下标
1 9 // 若 为0 则 表示叶子节点后一位表示权重
1 4
1 7
0 7
2 6 1
1 8
0 9
0 4
0 3
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
const int maxn = 1000000;
int n;
double p,r,ans =0;
//结构体存储权值以及孩子结点
struct
{
int data;
vector<int> v;
}node[maxn];
void dfs(int root , int depth)
{
if(node[root].v.size()==0)
{
ans += node[root].data * pow(1+r/100,depth);
return;
}//遇到叶子结点 则求和
for(int i =0 ; i < node[root].v.size();i++)
dfs(node[root].v[i] , depth + 1);
}
int main()
{
cin>>n>>p>>r;
for(int i = 0; i < n ;i ++)
{
int j;
cin>>j;
if(j)
{
int id;
for(int k =0 ; k < j; k++)
{
cin>>id;
node[i].v.push_back(id);
}
}
else
cin>>node[i].data;
}
dfs(0,0);
printf("%.1f",ans* p);
}
1053 Path of Equal Weight (30分)
//遍历树 输出所有到叶节点时权重和等于给定值的路径
//主要考点 树的遍历 保存路径
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 100000;
struct student
{
int weight;
vector <int> child;
}node[maxn];
int path[maxn],s;
bool cmp(int a,int b)
{
return node[a].weight > node[b].weight;
}
void dfs(int root ,int numnode,int sum)
{
if(sum > s)return;
if(sum == s)
{
if(node[root].child.size()!=0) return;
//判断并输出路径
for(int i = 0; i < numnode ; i++)
{
printf("%d",node[path[i]].weight);
if(i < numnode - 1) cout<<" ";
else
cout<<endl;
}
}
for(int i = 0 ; i < node[root].child.size();i++)
{
int child = node[root].child[i];
path[numnode] = child;//就一个普普通通的数组存储这一步的结点 因为递归的性质 numnode 会覆盖其他的路径 就很妙
dfs(child,numnode+1,sum + node[child].weight);
}
}
int main()
{
int n,m;
cin>>n>>m>>s;
for(int i = 0; i < n ; i++ )
cin>>node[i].weight;
for(int i = 0 ; i < m ; i++)
{
int id,digit;
cin>>id>>digit;
for(int j = 0; j < digit ; j++)
{
int son;
cin>>son;
node[id].child.push_back(son);
}
//这一步把结点排序 这样先遍历权重较大的结点
sort(node[id].child.begin(),node[id].child.end(),cmp);
}
path[0] = 0;
dfs(0,1,node[0].weight);
}
(九)二叉查找树(BST)
(一)简介
Binary Search Tree、排序二叉树、
左子树所有结点的数据域 都小于 右子树的 结点数据域
(二)操作集
//查找
void search(node* root,int x)
{
if(root == NULL)
{
cout<<"search failed\n";
return;
}
if(x == root -> data)
{
cout<<root -> data;
}
else if(x < root -> data)
search(root -> left,x);
else
search(root -> right,x);
}
//对于二叉查找树 其内部数据的顺序是一定的 若查询失败 那么失败的位置一定是其插入的位置
void insert(node* &root , int x)
{
if(root == NULL)
{
root = newnode(x);
return ;
}
if(x == root -> data)
return;
else if(root -> data < x)
insert(root -> left , x);
else insert(root -> right,x);
}
node* create(int data[] , int n)
{
node* root = NULL;
for(int i = 0 ; i < n;i++)
{
insert(root,data[i]);
}
return root;
}
//删除操作
//对于删掉一个根节点 一种方法是找出找出左子树中最大的结点
//覆盖掉根节点
//另一种则是在右子树找到的最小的结点覆盖根节点
//左子树中最大的结点只需要从它的根节点一直向右寻找
//右子树最小的结点反之亦然
node* findmin(node* root)
{
while(root -> right)
root = root -> right;
return root;
}
node* findmax(node* root)
{
while(root -> left)
root = root -> left;
return root;
}
(1)如果当前结点为空说明不存在 直接返回;
(2)如果找到了 开始进入删除环节
a:如果是叶子结点 直接删除
b:如果存在左孩子,寻找前驱pre 让pre覆盖root
再递归删除pre;
c:如果存在右孩子 同理
(3)如果结点值大于x,向左子树递归;
(4)如果结点值小于x,向右子树递归;
void deletenode(node* &root , int x)
{
if(root == NULL) return;
if(root -> data == x)
{
if(root -> left == NULL && root -> right == NULL)
root = NULL;
else if(root -> left != NULL)
{
node* pre = findmax(root -> left);
root -> data = pre -> data;
deletenode(root -> left,pre -> data);
}
else
{
node* pre = findmin(root -> right);
root -> data = pre -> data;
deletenode(root -> right , pre -> data);
}
}
else if(root -> data > x)
deletenode(root -> left , x);
else
deletenode(root -> right,x);
}
1043 Is It a Binary Search Tree (25分)
// 给出一组数据 建立二叉搜索树 问它的先序或
//镜像先序是否等于这个初始序列
//如果是 则输出对应的后序
#include<iostream>
#include<vector>
using namespace std;
const int maxn = 10000;
vector<int>origin,pre,prem,post,postm;
struct node
{
int data;
node* left,*right;
};
void insert(node* & root , int x)
{
if(root == NULL)
{
root = new node;
root -> data = x;
root -> left = root -> right = NULL;
return ;
}
if(x < root -> data) insert(root -> left , x);
else insert(root -> right , x);
}
void preorder(node* root)
{
if(root == NULL)
return;
pre.push_back(root -> data);
preorder(root -> left);
preorder(root -> right);
}
void premirror(node* root)
{
if(root == NULL)
return;
prem.push_back(root -> data);
premirror(root -> right);
premirror(root -> left);
}
void postoeder(node * root)
{
if(root == NULL)
return ;
postoeder(root -> left);
postoeder(root -> right);
post.push_back(root -> data);
}
void postmirror(node * root)
{
if(root == NULL)
return ;
postmirror(root -> right);
postmirror(root -> left);
postm.push_back(root -> data);
}
int main()
{
node* root = NULL;
int n;
cin>>n;
int array[maxn];
for(int i =0 ; i < n ; i++)
{
int id;
cin>>id;
origin.push_back(id);
insert(root,id);
}
preorder(root);
premirror(root);
postoeder(root);
postmirror(root);
if(origin == pre)
{
cout<<"YES"<<endl;
for(int i = 0 ; i < post.size();i++)
{
if(i)
cout<<" ";
cout<<post[i];
}
}
else if(origin == prem)
{
cout<<"YES"<<endl;
for(int i = 0; i < postm.size();i++)
{
if(i)
cout<<" ";
cout<<postm[i];
}
}
else
cout<<"NO";
}
1099 Build A Binary Search Tree (30分)
知道二叉搜索树的结构 和数据 我们可以把它还原
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 100000;
int oridinary[maxn],bst[maxn];
int index=0,n;
struct Node
{
int data;
int left , right;
}node[maxn];
//核心还原代码
void dfs(int root)
{
if(root == -1)
return ;
//一直向左递归到底了就是其第一个插入位置
dfs(node[root]. left);
node[root].data = oridinary[index++];
dfs(node[root]. right);
}
int digit =0 ;
void levelorder(int root)
{
queue<int> q;
q.push(root);
while(!q.empty())
{
int a = q.front();
q.pop();
if(digit)
cout<<" ";
cout<<node[a].data;
digit ++;
if(node[a].left != -1) q.push(node[a].left);
if(node[a].right != -1)q.push(node[a].right);
}
}
int main()
{
cin>>n;
for(int i = 0; i < n ; i++)
{
cin>>node[i].left>>node[i].right;
}
for(int i = 0; i < n;i++)
cin>>oridinary[i];
sort(oridinary,oridinary+n);
dfs(0);
levelorder(0);
}
(十)平衡二叉树
(1)简介
对于序列1 2 3 4 5 若构建二叉查找树 会得到一条长链式
的树 即变成链表
AVL树要求左右子树高度差距不超过1
(2)构建
struct node
{
int v,height; // 增加了height 记录当前子树高度
node* lchild ,*rchild;
};
node * newNode(int v)
{
node * Node = new node;
Node -> v = v;
Node -> heght = 1;
Node -> lchild = Node -> rchild = NULL;
return Node;
}
int getheight(node * root)
{
if(root -> NULL) return 0;
return root -> height;
int getBalanceFactor(node* root)
{
return getheight(root -> lchild) - getheight(root -> rchild);
}
void updateHeight(node * root )
{
root -> height = max(getheight(root -> lchild),getheight(root -> rchild)) + 1 ;
}
(三)操作集
查找与二叉查找树无异 略
void LeftRotation(node * & root)
{
node * temp = root -> lchild;
//将root右儿子标记为temp
root -> rchild = temp -> lchild;
//step1 根节点右儿子变成temp左儿子
temp -> lchild = root ;
//step2 temp 左儿子变成根节点 旋转过程
updateheight(root);
updateheight(temp);
root = temp;
//根结点变成temp
}
void rightRotation(node* & root)
{
node * temp = root -> lchild;
//temp 为根节点左儿子 为右旋做准备
root -> lchild = temp -> rchild;
//step 1 根节点左儿子变成temp的右儿子
temp -> rchild = root;
//step temp右儿子指向root;
updateheight(root);
updateheight(temp);
root = temp;
}
插入
void insert(node * & root)
{
if(root == NULL)
{
root = newNode(v);
return ;
}
if(v < roott -> v)
{
insert(root -> lchild,v);
updateheight(root);
if(getBalanceFactor(root ) == 2)
{
if(getBalanceFactor(root -> left)==1)
rightRotation(root);
else if(getBalanceFactor(root -> left) ==-1)
{
leftrotation(root -> lchild);
rightrotation(root);
}
}
}
else
{
insert(root -> rchild,v);
updateheight(root);
if(getBalanceFactor(root) == -2)
{
if(getbalancefactor(root -> rchild) == -1)
leftrotation(root);
else if(getbalancefactor(root -> rchild) ==1)
{
rightrotation(root -> rchild);
leftrotation(root);
}
}
}
}
#include<iostream>
using namespace std;
struct node
{
int v,height;
node * lchild ,* rchild;
}* root;
node * newnode(int v)
{
node * Node = new node;
Node -> v = v;
Node -> height = 1;
Node -> lchild = Node -> rchild = NULL;
return Node;
}
int getheight(node* root)
{
if(root == NULL) return 0;
return root -> height;
}
void updateheight(node* root)
{
root -> height = max(getheight(root ->lchild) , getheight(root -> rchild)) + 1;
}
int getbalancefactor(node* root)
{
return getheight(root -> lchild) - getheight(root -> rchild);
}
void leftrotation(node* & root)
{
node* temp = root -> rchild;
root -> rchild = temp -> lchild;
temp -> lchild = root;
updateheight(root);
updateheight(temp);
root = temp;
}
void rightrotation(node* & root)
{
node* temp = root -> lchild;
root -> lchild = temp -> rchild;
temp -> rchild = root;
updateheight(root);
updateheight(temp);
root = temp;
}
void insert(node*&root,int v)
{
if(root == NULL)
{
root = newnode(v);
return;
}
if(v < root -> v)
{
insert(root -> lchild , v);
updateheight(root);
if(getbalancefactor(root) == 2)
{
if(getbalancefactor(root -> lchild) == 1)
rightrotation(root);
else if(getbalancefactor(root -> lchild) == -1)
{
leftrotation(root -> lchild);
rightrotation(root);
}
}
}
else
{
insert(root -> rchild , v);
updateheight(root);
if(getbalancefactor(root) == -2)
{
if(getbalancefactor(root -> rchild) == -1)
leftrotation(root);
else if(getbalancefactor(root -> rchild) == 1)
{
rightrotation(root -> rchild);
leftrotation(root);
}
}
}
}
int main()
{
int n,v;
cin>>n;
for(int i =0 ; i < n ; i++)
{
cin>>v;
insert(root,v);
}
cout<<root ->v;
}