树学

(一)简介

树的层次:根节点为第一层
结点的度:结点拥有的子树
叶子结点:度为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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值