算法筆記(樹專題)
阿新 • • 發佈:2018-03-21
body 層序 blog 位置 應該 入隊 delete lan new
//偽代碼 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); }
? 樹:即子結點個數不確定且子結點沒有先後次序的樹。推薦使用靜態寫法
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; }
算法筆記(樹專題)