Foreword:
Now in Android interviews, there are more and more questions about data structures, and I often see interview questions sent by others asking about red-black trees, binary tree search, etc., so although we will not have all kinds of difficult interviews right away However, at least the basic knowledge of trees must be known, so that we can learn further.
Post a picture of the introduction I saw recently:
Android Skill Book Series:
Android Basics
Android Skill Tree - Animation Summary
Android Skill Tree - View Summary
Android Skill Tree - Activity Summary
Android Skill Tree - Summary of View Event System
Android Skill Tree - Summary of Android Storage Path and IO Operation
Android skill tree - multi-process related summary
Android Skill Tree - Drawable Summary
Data Structure Fundamentals
Android Skill Tree - Array, Linked List, Hash Table Basic Summary
Android Skill Tree - Summary of Tree Basics (1)
Algorithm Basics
Android Skill Tree - Summary of the Basics of Sorting Algorithms
This article focuses on the basics of trees.
A tree is a finite set of n (n>=0) nodes. When n=0, it is called an empty tree. In any non-empty tree: (1) there is only one specific node called root (Root); (2) when n>1, the remaining nodes can be divided into m(m>O) There are mutually disjoint finite sets T1, T2, ..., Tm, each of which is itself a tree, and is called a subtree of the root (SubTree)
Basic knowledge
Node
Based on the basic knowledge above, I drew a summary diagram (so that I don't need to write a text introduction, ahaha):
tree structure features
Or to illustrate with a picture drawn by yourself:
storage structure
In the Android Skill Tree - Array, Linked List, Hash Table Basic Summary , we introduced linear storage, linked storage, and our tree can be fully represented by a combination of the two.
We will use the above methods to represent the storage structure of the following tree:
Parental notation:
In each node, an indicator is attached to indicate the position of its parent node in the array.
Because there are eleven nodes, our index is 0-10, and then stored in the index position (data + parent's index value), the result is shown in the following figure:
Here we find that according to the parent pointer in the index, it is easy to know the parent node, but for example, if I know the E node and want to know which child nodes are, I don't know, I can only pass the whole structure. traverse.
Of course, we can add an additional pointer in disguise:
If we pay more attention to the relationship between sibling nodes, we can add a right sibling domain to reflect the sibling relationship:
Children linked list notation:
Arrange the child nodes of each node and use a singly linked list as the storage structure, then n nodes have n child linked lists. If it is a leaf node, the singly linked list is empty. Then the n head pointers form a linear table, which is stored in a one-dimensional array using a sequential storage structure.
Representing our tree above in child notation, the structure is as follows:
So our node structure has two kinds: 1. The header node of the header array:
- The child node of the child linked list:
But this is convenient for finding the children of a certain node, or the brothers of a certain node, but it seems that it is troublesome to find the parents of a certain node. So we can combine the above-mentioned "Parent Representation"
Parent-child representation:
You can combine the above two methods.
Child brother notation:
For any tree, the first child of its node is unique if it exists, and its right sibling is also unique if it exists. So set two pointers, respectively pointing to the first child of the node and the right brother of the node
So it is similar to the above, except that we store two different pointers (from the method name, we know that the <child><brother> method, one child, one brother, two pointers).
We implement the above tree in this way:
Forest:
Continue to draw a picture to illustrate, save typing, hehe:
Classification
Trees are also classified according to different conditions, let's take a look.
What is the difference between an ordered tree and an unordered number?
If the subtrees of the nodes in the tree are considered to be in order from left to right and cannot be interchanged, then it becomes an ordered tree, otherwise it is an unordered tree
For example, we simply represent the relationship of a family:
For example, it only means that the children of A have B and C. At this time, it does not matter if B and C change the position of the leaf, and this time it is an unordered tree.
But if our family tree is sorted by age (eldest son, second son), then B and C cannot change positions at this time, and this is an ordered tree.
But the trees we usually refer to are usually ordered trees, and ordered trees have many categories, most of which are binary trees.
Binary tree:
Basic form:
Binary tree properties:
In fact, this is similar to the mathematical formula we had to memorize in our previous mathematics class. You can draw a binary tree by yourself, and then try to compare the above formula to see if it is correct.
Traverse a binary tree:
The traversal of the binary tree refers to starting from the root node and visiting all the nodes in the binary tree in a certain order, so that each node is visited sequentially and only once.
Preorder traversal:
Just looking at this picture, in fact, I can't understand the rules, but we only need to understand the rules.
伪代码:
遍历(结点对象 t){
if( t == null){
return;
}
//第一步,实现某个业务操作,比如我们是打印结点字符串。
print(t)
//第二步,递归方式继续调用该方法遍历左孩子
遍历(t.左孩子)
//第三步,递归方式继续调用该方法遍历右孩子
遍历(t.右孩子)
}
We see that because print comes before other methods, it is called preorder traversal. We now pass in the root node to this method, then print and recurse in turn, and we will find that it is the order on the graph.
Inorder traversal:
伪代码:
遍历(结点对象 t){
if( t == null){
return;
}
//第一步,递归方式继续调用该方法遍历左孩子
遍历(t.左孩子)
//第二步,实现某个业务操作,比如我们是打印结点字符串。
print(t)
//第三步,递归方式继续调用该方法遍历右孩子
遍历(t.右孩子)
}
We found that as long as we put our print statement in the middle, it is in-order traversal.
Post-order traversal:
伪代码:
遍历(结点对象 t){
if( t == null){
return;
}
//第一步,递归方式继续调用该方法遍历左孩子
遍历(t.左孩子)
//第二步,递归方式继续调用该方法遍历右孩子
遍历(t.右孩子)
//第三步,实现某个业务操作,比如我们是打印结点字符串。
print(t)
}
We found that as long as we put our print statement at the end, it is post-order traversal.
Binary tree classification:
Oblique tree:
Complete binary tree and full binary tree:
A binary tree with a depth of k and 2^(k+1) - 1 nodes is called a full binary tree. The characteristic of this tree is that the number of nodes on each layer is the maximum number of nodes.
In a binary tree, if all layers except the last layer are full, and the last layer is either full or lacks several consecutive nodes on the right, the binary tree is a complete binary tree.
Balanced binary tree:
There is a lot of knowledge about this, which will be added later.
Sort binary tree:
There is a lot of knowledge about this, which will be added later.
Threaded binary tree:
A binary linked list of n nodes contains n+1 (2n-(n-1)=n+1) null pointer fields. Use the null pointer field in the binary linked list to store pointers to the predecessor and successor nodes in a certain traversal order (this additional pointer is called "clue").
A knowledge point must be explained here: what are predecessors and successors.
Many people on the Internet are too simple to explain this so that many people misunderstand, such as:
Suppose we now have this a binary tree:
For example, a doubly linked list has predecessors and successors. Then we can't see the tree simply by looking at it. We must first arrange the tree in a linked list form when it is traversed in a certain way, and then we can know what the predecessor and successor of a node are, such as In the above figure, we use in-order traversal, and what we get is: HDIBJEAFCG, at this time, the predecessor of I is D, and the successor is B.
We have two pointers to its two child nodes in the binary tree storage structure.
But there may be only one child node, or no child node, so this empty pointer storage is wasted, we can store the pointer of the predecessor or successor node of this node in this pointer.
But there is another problem at this time, that is, we don't know whether the pointer of the predecessor or the left child node is currently placed at this point, so we also need a parameter to indicate which pointer is currently placed at this position.
- When ltag is 0, it indicates that lchild is the pointer of the left child of the node, and when it is 1, it indicates that lchild is the predecessor of the node.
- When rtag is 0, it means that rchild is the pointer of the right child of the node, and when it is 1, it means that rchild is the successor of the node.
Storage structure:
Binary tree sequential storage structure:
We supplement the binary tree as a full binary tree, and then fill in a one-dimensional array accordingly.
Binary linked list:
Each node of the binary tree has at most two children, so design a data field and two pointer fields for it.
Trident linked list:
Improved in binary linked list, adding parent node guidance, can better achieve access between nodes
Conclusion:
This article is not finished, there is too much content, and it will be added later. Where is wrong, welcome to point out. . . thanks.
refer to:
"Dahua Data Structure"
"Wikipedia"