1. 程式人生 > >算法筆記(樹專題)

算法筆記(樹專題)

body 層序 blog 位置 應該 入隊 delete lan new

樹專題

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;
}

算法筆記(樹專題)