Data Structure Learning (C ++) - Binary Tree [2]

zhaozj2021-02-16  56

Train biopsy

This is the first difficult point in the data structure course. I don't know if you look like this. Anyway, I was a lot of brain cells - of course, the annoying matrix compression and related addition multiplication is not considered. . I have spent a lot of brain cells because of thinking: what do they do? Very happy, I saw this shadow book, this chapter was called *, although I didn't sure the author did an idea - clues in the PC in the current PC! - I don't know if I have done this conclusion, it will be killed, ^ _ ^.

In order to prove this conclusion, let's take a look at the reason why the linearized binary tree is: First, we want to use a few times, find a front drive or subsequent manner of a two-fork tree. Of course, this kind of operation is very frequent, it makes sense. Second, the leaf node of the binary tree has two pointer domains, which can save memory. Seriously, it is really delicious, and it is true that "waste use" is completely "waste use" - this person should really participate in environmental protection. But on the computer's dead plate, people 's integrity is often unable - for speed, the various components of the computer are neatly planned, and the idea is often built into complications.

Let's take a look at the two targets that traveled two forks can reach the above objectives.

The forward drive and successor of the linear sequence after traversal. The aforementioned lassification can be found in sequential, but the front drive requires parents; the pre-sequence linearization before the prior to the pre-priority is not required, but it is not very straight; the rear serology can be found in sequence, but after successive parents. It can be seen that the clues into the order is the best choice, which is basically the requirements.

Save memory. Add two flags, how is the two bits store? Even on the CPU stored in the support bit, it is also not possible to store the memory, and the first is that the address of the structural member is limited, and the second is that the number of bit memories is limited. Therefore, one byte is required to store these two flags. For speed and transplantation, in general, memory is to be aligned, in fact, there is no memory! However, when this space is used to store dual-pro pointers, the convenience is absolutely not a trail, and it has given a stack of non-recursion traversal. Also, inserting a deleted operation on the lines of the lines is too large.

In summary, the clues are preferably subordinate linearization (the pre-sequence linear is also available after the stack, why need to be linearized), at least 1 byte of the additional flag domain space, at 32-bit CPU request Aligned to 4 bytes, it is better than storing a dual-pro-pointer, and it can also achieve the purpose of neutralization, and can bring other benefits. So, the line-based binary tree is useless on the current PC!

Since there is nothing to understand for other systems, the following points of view are listened. There is a lot of memory space now, and there is a node 2 to 3 bytes. It doesn't mean it (actually because it is noticed); and there is a very valuable place in memory (such as a single-chip), you will try to avoid the use of tree structure - Utilize other methods. Therefore, it seems that the linen trigemine is really unused.

Binary search tree

This is probably the most important application of the binary tree. Its ideas is actually a natural thing - lookup value is left left down than the current node, the big turn right, etc., if it is, it is not found. The more natural things are better, the more you don't need me to talk nonsense. Before giveing ​​the implementation of the BST, we have to add a member function of a printed tree structure in the class of the binary tree so that the insertion and deletion process can be clearly seen.

PUBLIC:

Void print ()

{

Queue *> a; queue flag; OFSTream outfile ("out.txt"); btnode * p = root; btnode ZERO; BOOL V = true;

INT i = 1, Level = 0, H = height ();

While (i <2 << h)

{

IF (i == 1 << Level)

{

COUT << Endl << SETW (2 << (h - level)); Level ;

IF (v) cout << p-> data;

Else Cout << '';

}

Else

{

COUT << SETW (4 << (H - Level 1));

IF (v) cout << p-> data;

Else Cout << "

}

IF (p-> left) {a.push (p-> left); flag.push (true);}

Else {a.push (& zero); flag.push (false);

IF (P-> Right) {a.push (p-> right); flag.push (true);}

Else {a.push (& zero); flag.push (false);

P = a.front (); A.POP (); v = flag.front (); flag.pop (); i ;

}

Cout << Endl;

}

The core of the print tree is used to traverse the binary tree at a level, but the binary tree has many nodes in the left or right sub-tree. The more the links are, the larger the lower gap. In order to print according to the structure of the tree, the binary tree must be completed into a fully binary tree, so the following node knows what position is --a.push (& zero); but such a node cannot print it, so each node There is a sign that is printed. It is reasonable to say that the PAIR structure is very suitable. For the sake of simplicity, I use two queues in parallel, one placement point pointer --a, a print mark - Flag. In this way, the end of the loop cannot be a queue empty - never can't empty. When null, I will make up a node - but it has become the last node of the full binary tree 2 ^ (Height 1) - 1. - Huang Pei's definition of the height is that the height of the empty tree is -1.

For the output format, note that the nodes of the first, 2nd, and 8th, and in the same line, the domain width of the first node is half of the rear sequence node. The above functions can be displayed normally at the level of the tree. When height <= 4), it must be output to the file to go to the file to go to the file outfile; - If the hierarchy is more It doesn't make sense to print out.

Implementation of binary search tree

In fact, in addition, insertion, delete, and lookup is added based on the binary tree.

#include "basetree.h"

Template

Class Bstree: Public Btree

{

PUBLIC:

BTNode * & Find (const t & data)

{

BTNODE ** P = & root; current = null; while (* p)

{

IF ((* P) ​​-> DATA == DATA) BREAK;

IF ((* p) -> Data right);

Else {current = * p; p = & ((* p) -> left);

}

Return * p;

}

Bool Insert (Const T & DATA)

{

BTNODE * & P = Find (data); if (p) Return False;

P = New btNode (Data, NULL, NULL, CURRENT); RETURN TRUE;

}

Bool Remove (Const T & DATA)

{

Return Remove (Find (DATA));

}

Private:

Bool Remove (btNode * & P)

{

IF (! p) returnaf false; btnode * t = p;

IF (! p-> left ||! p-> right)

{

IF (! p-> left) p = p-> Right; Else P = P-> Left;

IF (p) p-> parent = current;

DELETE T; RETURN TRUE;

}

T = P-> Right; while (t-> left) t = t-> left; p-> Data = t-> data; current = t-> Parent;

Return Remove (current-> left == T? current-> left: current-> right);

}

}

The above code is a bit notes, it is necessary to explain that the implementation of nonlinear chain structure operation is very good. INSERT and REMOVE are based on find, so you must maximize the use of these two operations.

l For INSERT, you need to modify the pointer content when the lookup fails, obviously this is an internal pointer (inside the dual-pro-node, rather than pointing to the node outside the node like root and current), which requires Find to return an internal pointer. However, after C reference is bound to an object, it cannot be changed, so the implementation within the Find is a two-pointer. The Insert operation also needs to modify the PARENT node domain of the inserted node, so a pointer to the node where you can be accessed by INSERT is generated in Find, which is used here. In fact, the pointer references returned by Find is not current-> left is current-> right. In this way, INSERT is very simple.

l For REMOVE, you need to modify the pointer content when you find success, is also an internal pointer. Based on find, it is easy to get references to this internal pointer (btNode * & P = Find (DATA).

Ø In the P-> Left and P-> Right, there is at least one of the null, if p-> left == null, then re-connect the right sub-tree P = P-> Right, in turn, reinstall the left Tree P = P-> LEFT. Note that the case of the left and right sub-trees is also included in these two operations - reinstall the right child when p-> left == null, and this time P-> Right is also null - therefore do not have to column come out. If the P is not empty, you need to modify P-> Parent = Current. Ø If P-> LEFT and P-> Right are not empty, it can be converted to have a empty. For example, a sequential ordered sequence [1, 2, 3, 4, 5], suppose 3 has both the left sub-tree and the right subtree, then its pre-drive 2 has a lack of right trees, and then 4 must miss the left sub-tree. . [Note 1] This way to delete node 3 is equivalent to delete node 4 from [1, 2, 3 (4), 4, 5]. This allows for at least one method in the case of NULL in P-> LEFT and P-> RIGHT. Did not change the binding object due to the C reference, this is to be solved using recursive, but also only recursive once. If you use a dual pointer to be full of stars, this is clearly the reason why the end is not eliminated.

[Note 1] This is because if there is a left subtree and a right man tree, then 2 must be on the left subtree of 3, 4 must be on the right of 3; if 2 has a right tree, then There should be a node between 2 and 3; if 4 has a left subtree, there should be a node between 3 and 4.

[Gossip] About the Remove Operation P-> LEFT and P-> Right does not explain the explanation of the method of processing, from Yan Weimin's courseware, I suddenly turned over, I really don't know why she own "data Structure (C language version) "It is so difficult to write here, I didn't understand it.

转载请注明原文地址:https://www.9cbs.com/read-22976.html

New Post(0)