算法笔记(树专题)

Posted dear_diary

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法笔记(树专题)相关的知识,希望对你有一定的参考价值。

树专题

1.DFS模板

 

//伪代码
void DFS(一个结点){
    访问该结点;
    for(遍历该结点的相邻未访问过的结点){
        选此结点;
        DFS(这个邻接结点);
        去掉刚刚选的结点;   //****(勿忘)
    }
}

 

2.BFS模板

//BFS使用队列
void BFS(int s){
    queue<int> q;
    q.push(s);  //起始点入队
    while(!q.empty()){
        取出队首元素top;
        访问队首元素top;
        将队首元素出队;
        将top的下一层结点中未曾入队的结点全部入队,并设置为已入队;
    }
}
for(结点未被访问){
    BSF(该结点);
}

3.二叉树的动态实现(指针)

struct node{
    int data;
    int layer;//层次遍历需要
    node* lchild;
    node* rchild;
};
//由于在二叉树建树前根节点不存在,因此其地址一般设为NULL ********
node* root = NULL;
//生成一个新结点
node* newNode(int v){
    node* Node = new node;
    Node->data = v;
    Node->lchild = Node->rchild = NULL;
    return Node;
}
//insert函数将在二叉树中插入一个数据域为x的新结点
void insert(node* &root, int x){ //(注意root要使用引用)****
    if(root == NULL){
        //root = newNode(x);
        root = new node;
        root->data = x;
        root->lchild = root->rchild = NULL;
        return;
    }
    if(由二叉树性质,x应该插在左子树){
        insert(root->lchild, x);
    } else{
        insert(root->rchild, x);
    }
}
//层序遍历
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 != NULL) {
            now->lchild->layer = now->layer + 1;
            q.push(now->lchild);
        }
        if(now->rchild != NULL) {
            now->rchild->layer = now->layer + 1;
            q.push(now->rchild);
        }
    }
}

4.二叉树的静态实现

 

 

struct Node{
    int data;
    int lchild;
    int rchild;
} node[maxn];
//先序遍历
void preorder(int root){
    if(root == -1) return;  //到达空树,递归边界,一般空树设为-1
    printf("%d\n", node[root].data);
    preorder(node[root].lchild);
    preorder(node[root].rchild);
}
//中序遍历
void inorder(int root){
    if(root == -1) return;
    inorder(node[root].lchild);
    printf("%d\n", node[root].data);
    inorder(node[root].rchild);
}
//后序遍历
void postorder(int root){
    if(root == -1) return;
    postorder(node[root].lchild);
    postorder(node[root].rchild);
    printf("%d\n", node[root].data);
}
struct Node{
    int data;
    int lchild;
    int rchild;
} node[maxn];
//先序遍历
void preorder(int root){
    if(root == -1) return;  //到达空树,递归边界,一般空树设为-1
    printf("%d\n", node[root].data);
    preorder(node[root].lchild);
    preorder(node[root].rchild);
}
//中序遍历
void inorder(int root){
    if(root == -1) return;
    inorder(node[root].lchild);
    printf("%d\n", node[root].data);
    inorder(node[root].rchild);
}
//后序遍历
void postorder(int root){
    if(root == -1) return;
    postorder(node[root].lchild);
    postorder(node[root].rchild);
    printf("%d\n", node[root].data);
}

5.树的遍历、树的静态写法

? 树:即子结点个数不确定且子结点没有先后次序的树。推荐使用静态写法

struct Node{
    int data;  //数据域
    int layer; //用于树的层次遍历
    vector<int> child;   //*****指针域,存放所有子结点的下标
} node[maxn];  //结点数组,maxn为结点上限个数
//树的先根遍历 或 DFS
void PreOrder(int root){
    printf("%d ", node[root].data);   //访问当前结点
    for(int i=0; i<node[root].child.size(); i++){
        PreOrder(node[root].child[i]);   //递归访问结点root的所有子结点
    }
}
//树的层次遍历 或 BFS
void BFS(int root){
    queue<int> Q;
    Q.push(root); //将根结点入队
    node[root].layer = 0; //记根结点的层号为0
    while(!Q.empty()){
        int front = Q.front();
        Q.pop();  //取出队首元素
        printf("%d ", node[front].data); //操作,如打印当前结点的数据域
        for(int i=0; i<node[front].child.size(); i++){
            int child = node[front].child[i];  //当前结点的第i个子结点的编号
            node[child].layer = node[front].layer + 1; //子结点层号为当前结点层号+1
            Q.push(child);   //将当前结点的所有子结点入队
        }
    }
}

6.知道二叉树的先序和中序遍历,建立该二叉树

struct Node{
    int data;
    Node *lchild, rchild;
};
int pre[MAXN], in[MAXN], post[MAXN];  //先序、中序及后序
//当前二叉树的先序序列区间为[preL, preR],中序序列区间为[inL, inR]
//create函数返回构建出的二叉树的根节点地址
Node* create(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(in[k] == pre[preL]){  //在中序序列中找到in[k] == pre[L]的结点
            break;
        }
    }
    int numLeft = k - inL;  //左子树的结点个数
    //返回左子树的根结点地址,赋值给root的左指针
    root->lchild = create(preL+1, preL+numLeft, inL, k-1);   //****注意参数怎么表示
    //返回右子树的根结点地址,赋值给root的右指针
    root->rchild = create(preL+numLeft+1, preR, k+1, inR);
    return root;
}

7.二叉树查找(BST)

//****search函数查找二叉查找树中数据域为x的结点
void search(node* root, int x){
    if(root == NULL){ //空树,查找失败
        printf("search failed\n");
        return;
    }
    if(x == root->data){
        printf("%d\n", root->data);
    }else if(x < root->data){//如果x比根节点的数据域小,说明x在左子树
        search(root->lchild, x);  //往左子树搜索
    }else{
        search(root->rchild, x);
    }
}
//****insert函数将在二叉树中插入一个数据域为x的新结点(注意参数root要加引用 &)
void insert(node* &root, int x){
    if(root == NULL){ //空树,查找失败,也即插入位置
        root = newNode(x);   //新建结点,权值为x
        return;
    }
    if(x == root->data){  //查找成功,说明结点已存在,直接返回
        printf("%d\n", root->data);
    }else if(x < root->data){//如果x比根节点的数据域小,说明x需要插在左子树
        insert(root->lchild, x);  //往左子树搜索
    }else{
        insert(root->rchild, x);
    }
}
//****二叉查找树的建立
node* create(int data[], int n){
    node* root = NULL;  //新建根节点root
    for(int i=0; i<n; i++){
        insert(root, data[i]);  //将data[0]~data[n-1]插入二叉查找树
    }
    return root;  //返回根节点
}
//寻找以root为根结点的树中最大权值结点
node* findMax(node* root){
    while(root->rchild != NULL){
        root = root->rchild;   //不断往右,直到没有右孩子
    }
    return root;
}
node* findMin(node* root){
    while(root->data !=NULL){
        root = root->lchild;
    }
    return root;
}
//删除以root为根结点的树中权值为x的结点(****)
void deletNode(node* &root, int x){
    if(root == NULL) return;  //不存在权值为x的结点
    if(root->data == x){//找到欲删除的结点
        if(root->lchild == NULL && root->rchild == NULL){ //叶子结点直接删除
            root = NUUL; //把root地址设为NULL,父结点就引用不到它了
        }else if(root->lchild != NULL){ //左子树不空时
            node* pre = findMax(root->lchild);  //找root前驱
            root->data = pre->data;  //用前驱覆盖root
            deleteNode(root->lchild, pre->data);  //在左子树中删除结点pre
        }else{//右子树不为空时
            node* next = findMin(root->rchild);  //找root后继
            root->data = next->data;  //用后继覆盖root
            deleteNode(root->rchild, next->data);  //在右子树中删除结点next
        }else if(root->data > x){
            deleteNode(root->lchild, x); //在左子树中删除x
        }else{
            deleteNode(root->rchild, x);  //在右子树中删除x
        }
    }
}

8.平衡二叉树 AVL

struct node{
    int v, height; //v为结点权值,height为当前子树高度
    node *lchild;
    node *rchild;
} *root;
//生成一个新结点
node* newNode(int v){
    node* Node = new node;
    Node->v = v;
    Node->height = 1;  //AVL需要
    Node->lchild = Node->rchild = NULL;
    return Node;
}
//获取以root为根结点的子树的当前height
int getHeight(node* root){
    if(root == NULL) return 0;
    return root->height;
}
/更新结点root的height
void updateHeight(node* root){
    //max(左孩子结点的height, 右孩子结点的height)+1
    root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
}
//计算结点的平衡因子
int getBalanceFactor(node* root){
    //左子树高度减右子树高度
    return getHeight(root->lchild) - getHeight(root->rchild);
}
//左旋
void L(node* &root){
    node* temp = root->rchild;
    root->rchild= temp->lchild;
    temp->lchild= root;
    updateHeight(root);
    updateHeight(temp);
    root = temp;
}
//右旋
void R(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){  //v比根结点权值小
        insert(root->lchild, v);  //往左子树插入
        updateHeight(root);  //更新树高
        if(getBalanceFactor(root) == 2){
            if(getBalanceFactor(root->lchild) == 1){  //LL型
                R(root);
            } else if(getBalanceFactor(root->lchild) == -1){  //LR型
                L(root->lchild);
                R(root);
            }
        }
    } else{  //v比根结点权值大
        insert(root->rchild, v);  //往右子树插入
        updateHeight(root);  //更新树高
        if(getBalanceFactor(root) == -2){
            if(getBalanceFactor(root->rchild) == -1){  //LL型
                L(root);
            } else if(getBalanceFactor(root->rchild) == 1){  //RL型
                R(root->rchild);
                L(root);
            }
        }
    }
}
//AVL树的建立
node* Create(int data[], int n){
    node* root = NULL;
    for(int i=0; i<n; i++){
        insert(root, data[i]);
    }
    return root;
}

 

以上是关于算法笔记(树专题)的主要内容,如果未能解决你的问题,请参考以下文章

算法笔记(图专题)

数据结构专题-学习笔记:Link Cut Tree 动态树

[算法]死磕二叉树专题算法

《寒假算法集训》(专题十八)字典树

《寒假算法集训》(专题十六)二叉搜索树

每日算法题 | 剑指offer 二叉树专题 (16) 平衡二叉树