In the previous introductory diagram article, we learned that graph is an abstract representation of the relationship between things, and based on the concept of graphs, we take out all the non-loop graphs and give them a new name-the tree.
There are a lot of conceptual terms about trees, so let's start with a simple two-fork tree (a root with up to two subtrees) for analysis.
This is some simple two-fork tree, where a, B, C and so on we become nodes. A is called the root node, its two branches are B and C, and we call B is a left subtree, C is a right sub-tree, knowing these simple concepts, we can initially explore some of the problems.
Binary tree as a special kind of graph, we should also study the way of its traversal, as we study the general graph of the way of traversal. Because its basic structure includes root, Zuozi, right subtree, we can change the output of these three elements to get different traversal order when we traverse.
Recursive definition of a pre-order traversal: For a node, access and output the root information, traverse the left subtree according to the preamble, and traverse the right subtree according to the preamble.
Recursive definition of Middle sequence traversal: For a node, traverse the left subtree according to the middle order, access the information of the output root, and traverse the right subtree according to the middle order.
Recursive definition of post-order traversal: For a node, follow the next step to traverse the left subtree, and follow the order to traverse the right subtree; Access and output the root information.
Take d For example, the pre-sequence traversal: 124536,; Middle sequence traversal: 425361; post-order traversal: 452631.
It is worth noting that, in addition to the sequence traversal, the other two traversal methods can be generalized to K-fork tree, because for the middle sequence traversal, every time the left dial hand tree, will access the root node, which will cause multiple repeated access to the root node, there is no "traversal" of the two words.
And for a given pre (post) sequence traversal and the middle sequence traversal of the two-tree, can be uniquely determined.
So let's look at a question about the three kinds of traversal of the binary tree (problem source:pku2255)
The main topic: Give a binary tree of the pre-sequence traversal, the middle sequence traversal, let you output its post-order traversal.
Mathematical analysis: According to its definition, three kinds of traversal methods are generated by recursion, then now know the two ways of traversal, but also can restore the original two-fork tree.
For example, taking the first set of data, the pre-order traversal is DBACEGF, the middle sequence traversal is ABCDEFG, then we through the definition of the pre-order traversal, we know that D is the largest tree root, at this time we then through the middle sequence traversal, ABC on the left side of D, is the left subtree, and EFG in D right side, the right This allows you to draw a tree initially. Then we are looking for the second point of the pre-order traversal ... In the end, the original two-fork tree must be restored.
Here the topic requires direct output after the post-traversal, then we restore the binary tree at the same time can also construct a post-sequential traversal. In the starting situation, the first point of the pre-sequence traversal as the root of the whole tree is to be used as the last point of the post-order traversal, which is we then through the middle sequence traversal and pre-sequence traversal to find the right subtree under this root, we see the right subtree as a whole, through the pre-sequence traversal can find a root, and then through this root and Saozi right sub-tree ... Until this root has no subtree.
The left sub-tree is then constructed.
This is the first to find the root and then find the right sub-tree looking for left dial hand tree, and the post-traversal recursive concept echoes.
Programming implementation: Through the above description, the construction process is essentially a recursive, but also can be said to traverse the map we are familiar with the deep search.
The reference code is as follows.
#include <iostream>#include<string.h>using namespacestd;Charpreorder[ -];Charmidorder[ -];Charpostorder[ -];intLen;voidTravelintPrestar,intPreend,intMidSTAR,intmidend) { if(Prestar > Preend)return; postorder[--len] = Preorder[prestar];//Record Root if(Prestar = = preend)return; inti; for(i =0; I <= midend;i++) if(Midorder[i] = =Preorder[prestar]) Break; Travel (Prestar+ I-midstar +1, Preend, i +1, midend);//left dial hand treeTravel (Prestar +1, Prestar + I-midstar, MidSTAR, I-1);//Right sub-tree }intMain () { while(cin>>preorder>>Midorder) {Len=strlen (preorder); Postorder[len]=' /'; Travel (0, len-1,0, len-1); cout<< postorder<<Endl; }}
we'll show you some of the other applications of tree structure in storing information.
First we introduce the segment tree.
segment tree, as the name implies, must be related to the line, we have a line segment [1,n] on the whole point to store information, and then a two-point method to form a complete binary tree to store this information, and can also access to find, update data, such as a series of operations, In the analysis of the specific problems that follow, we will discuss them. The
segment tree solves a lot of problems, and here we start with a simple question about the learning of the segment tree--The maximum value of the specified interval. (Problem source:hdu1754)
The topic is very clear, mathematical analysis is not difficult, so here we focus on the implementation of its programming.
We first divide the whole problem into functional, and then consider the implementation of the modular function. In the above problem, we want to complete the storage of data, access to data to get the maximum value, update data.
Here Perhaps people will consider using arrays directly to record and traverse to find the maximum, but this method, first, the brute force time is too high complexity; second, this method is difficult to complete the update of the data. So here we consider constructing a line tree.
Storage of data: That's what we call building a tree. Here we will construct the binary search (DFS) and record the maximum value of its Saozi right subtree at each non-leaf node, which is achieved by deep searching and backtracking. At this point, if we consider the N person's score as the "carrying" of the integer on the line segment [1,n], then each non-leaf node records the maximum value on the interval segment when the whole tree is constructed.
Access data to get the maximum: here we still need to use a binary search idea, and then match the desired interval with the information we have constructed for the segment tree to get the answer.
Update data: This is still based on binary lookup (because the dichotomy is used to construct the segment tree, which is the echo of the exact binary tree that we are constructing), and once the leaf node is located, the data is updated. And then do the same as the retrospective operation of the work of the entire book node to be updated again.
With the above analysis of the programming process, it is not difficult to understand the code.
The reference code is as follows. (>> and << operation in the code, nothing more than/2 or * * *, here is to get the line segment tree in the corresponding array subscript, the reader a little simulation to know why the code is so written).
#include <cstdio>#include<cmath>using namespacestd;intmax[4000001];intMaxintAintb) { returnA>b?a:b;}voidPushup (intIndex//backtracking constructs a segment tree{Max[index]= Max (max[index<<1],max[(index<<1)+1]);}voidBuildintLintRintIndex//Create a line segment tree{ if(L = =r) {scanf ("%d",&Max[index]); return; } intm = (L + r) >>1; Build (L,m,index<<1); Build (M+1, R, (index<<1)+1); Pushup (index);}voidUpdateintPintQintLintRintIndex//Update Data{ if(L = =R) {Max[index]=Q; return; } intm = (r+l) >>1; if(P <=m) Update (P,q,l,m,index<<1); ElseUpdate (P,q,m+1, R, (index<<1)+1); Pushup (index);}intGetmax (intLintRintLintRintIndex//access to data for a given interval{ if(L<=l && R >=R)returnMax[index]; intm = (r+l) >>1; intRET =0; if(L <=m) Ret= Max (Ret,getmax (l,r,l,m,index<<1)); if(R >m) Ret= Max (Ret,getmax (l,r,m+1, R, (index<<1)+1)); returnret;}intMain () {intN, M, a, B, I; CharC; while(SCANF ("%d%d", &n,&m)! =EOF) {Build (1N1); for(i =0; I < m;i++) {scanf ("%*c%c%d%d",&c,&a,&b); if(c = ='Q') printf ("%d\n", Getmax (A, B,1N1)); ElseUpdate (A, B,1N1); } }}
Based on a simple understanding of the "graph theory and its application – the diagram", here we will continue to discuss the "tree" problem. First, some concepts are introduced here.
The so-called spanning tree, simply for graph graph--g (v,e) with a connected component of 1, we find a sub-figure T (v ', E ') of G, where V = V ', E ' can be a subset of E.
The corresponding generating forest, which is the graph graph of the connected component n, we analyze each connected component separately, get the spanning tree, and finally group together become the forest.
The so-called minimum spanning tree is that if the point set E of the given graph--g (v,e) is a weighted value (that is, the value is stored on this side), in all spanning trees, the smallest of the weights is the minimum spanning tree.
The above definitions appear to be very abstract, and we will be more aware of the specific problems.
So let's take a concrete example to analyze it. (Problem Source:hdu 1301)
The main topic: through the keyboard input to you a graph graph--g (v,e), where the edge set E is a weighted value (that is, the link between the edge of the storage value), now you find a sub-map, requires that the sub-diagram can be connected to all the points in the original image (that is, the diagram is the original tree), And the weight of this spanning tree is the smallest of all spanning trees, the smallest spanning tree. Mathematical analysis: The algorithm for generating the minimum spanning tree, common with prim algorithm and Kruskal algorithm, here we will introduce Kruskal algorithm.
Its specific steps are as follows.
1. We set G (V,e) is the original (point set V contains n elements), G ' (V ', E ') is the smallest spanning tree. We will first sort the edge set E with the weighted value.
2. Our husband becomes G ' (v,∅), then expediency the smallest edge of the value to try to build the minimum spanning tree g ', if adding the current minimum edge causes the ring to be discarded, discard the current edge.
3. Traversing all edges, if the n-1 bar can be selected, the minimum spanning tree is obtained, otherwise, only the smallest forest can be generated.
The Kruskal algorithm is based on greedy thinking. In order to get the spanning tree, we want to select the N-1 element in the edge set E, which is the minimum number of edges to ensure that the point set with n elements is connected, then we only need to start with the smallest weighted edge. In this construction process, if an edge occurs that causes the spanning tree to ring, then we need at least n edges to construct the birth tree (which is obvious). At this point we have two options, one option is to discard this edge, we construct the n-1 element of the Edge set V ', the other option is to take this edge, construct n elements of the Edge set V '. We can make the answer simply by comparing it. E = {E1,e2,e3,e4,e5,e6} (in ascending order of weights) here we assume that a ring is generated at E3.
Scenario One: E1,e2,e4,e5.
Scenario Two: E1,e2,e3,e4,e5,e6. (because the E3 that led to the formation of the ring have no effect on the connectivity of the spanning tree, the point behind the E3 is exactly the same as the scheme one, but one more element) it is obvious that scheme one is using the optimal construction method of greedy thought. The above is the Kruskal algorithm for generating the minimum spanning tree.
Programming implementation: With the above understanding of the Kruskal algorithm coupled with the understanding of the set, we are not difficult to implement it in the implementation of the program. It is worth mentioning that in the case of the set and the minimum spanning tree, it is often the graph graph which is essentially non-direction is treated as a graph, which is mainly for the convenience of programming.
The reference code is as follows.
#include <stdio.h>#include<string.h>using namespacestd;introot[ -];intFind (intt) { if(Root[t] = =t)returnT; Else returnROOT[T] =Find (Root[t]);}voidBingintXinty) { if(Find (x)! =Find (y)) { if(Find (x) <Find (y)) Root[find (y)]=Find (x); Elseroot[find (x)]=Find (y); }}intMain () {intn,i,j,k,x,y,min,sum,cost[ -][ -]; CharCH1,CH2; while(SCANF ("%d",&N), N) {GetChar (); memset (Cost,-1,sizeof(cost)); for(i =1; I < n;i++) {Root[i]=i; scanf ("%c%d",&ch1,&k); for(j =1; J <= k;j++) {scanf ("%c%d",&ch2,&x); COST[I][CH2-'A'+1] =x; } getchar (); } Root[n]=N; Sum=0; for(k =1; k < n;k++) {Min=100000; for(i =1; I < n;i++) { for(j = i +1; J <= n;j++) { if(Cost[i][j] >0&& find (i)! = Find (j) && Cost[i][j] <Min) {Min=Cost[i][j]; X= i, y =J; }}} bing (x, y); Sum+=Min; } printf ("%d\n", sum); } return 0;}
Graph theory and its application--tree