算法笔记(树专题)
//伪代码 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; }