mirror of
https://github.com/ClovertaTheTrilobita/SanYeCao-blog.git
synced 2026-09-04 20:55:41 +00:00
added coding language in en
This commit is contained in:
parent
d6cbb8ba3d
commit
ae2b5e4f5e
1 changed files with 14 additions and 14 deletions
|
|
@ -26,7 +26,7 @@ Putting facts aside, suppose there happens to be a binary tree right in front of
|
||||||
|
|
||||||
From a computer's perspective, however, for a binary tree defined like this:
|
From a computer's perspective, however, for a binary tree defined like this:
|
||||||
|
|
||||||
```
|
```c
|
||||||
#define ElemType int
|
#define ElemType int
|
||||||
typedef struct BiTNode{
|
typedef struct BiTNode{
|
||||||
ElemType data;
|
ElemType data;
|
||||||
|
|
@ -46,7 +46,7 @@ Imagine that we first obtain node $A$. There are three things we can do: **read
|
||||||
|
|
||||||
For preorder traversal, we first read the value and then explore the left and right children.
|
For preorder traversal, we first read the value and then explore the left and right children.
|
||||||
|
|
||||||
```
|
```c
|
||||||
void PreOrder(BiTree T) {
|
void PreOrder(BiTree T) {
|
||||||
if (T!=NULL) { // When the passed-in node T is not empty
|
if (T!=NULL) { // When the passed-in node T is not empty
|
||||||
visit(T); // Visit this node
|
visit(T); // Visit this node
|
||||||
|
|
@ -68,7 +68,7 @@ It is definitely not because I am lazy. Nope.
|
||||||
|
|
||||||
Similarly, inorder traversal simply places `visit()` in the middle.
|
Similarly, inorder traversal simply places `visit()` in the middle.
|
||||||
|
|
||||||
```
|
```c
|
||||||
void PreOrder(BiTree T) {
|
void PreOrder(BiTree T) {
|
||||||
if (T!=NULL) { // When the passed-in node T is not empty
|
if (T!=NULL) { // When the passed-in node T is not empty
|
||||||
PreOrder(T->lchild); // Enter the left child
|
PreOrder(T->lchild); // Enter the left child
|
||||||
|
|
@ -80,7 +80,7 @@ void PreOrder(BiTree T) {
|
||||||
|
|
||||||
There is no need for me to elaborate on postorder traversal either.
|
There is no need for me to elaborate on postorder traversal either.
|
||||||
|
|
||||||
```
|
```c
|
||||||
void PreOrder(BiTree T) {
|
void PreOrder(BiTree T) {
|
||||||
if (T!=NULL) { // When the passed-in node T is not empty
|
if (T!=NULL) { // When the passed-in node T is not empty
|
||||||
PreOrder(T->lchild); // Enter the left child
|
PreOrder(T->lchild); // Enter the left child
|
||||||
|
|
@ -126,7 +126,7 @@ Pretty simple, right? Let us consider how to implement it in code.
|
||||||
|
|
||||||
We need to maintain two additional variables in the binary tree structure.
|
We need to maintain two additional variables in the binary tree structure.
|
||||||
|
|
||||||
```
|
```c
|
||||||
typedef struct ThreadNode {
|
typedef struct ThreadNode {
|
||||||
ElemType data;
|
ElemType data;
|
||||||
struct ThreadNode *lchild, *rchild;
|
struct ThreadNode *lchild, *rchild;
|
||||||
|
|
@ -140,13 +140,13 @@ Suppose we have now reached node $D$. From the program's perspective, how can we
|
||||||
|
|
||||||
For the predecessor node, we need to define an additional global pointer variable. This way, when we move to the next node, we know who its predecessor is.
|
For the predecessor node, we need to define an additional global pointer variable. This way, when we move to the next node, we know who its predecessor is.
|
||||||
|
|
||||||
```
|
```c
|
||||||
ThreadNode *pre = NULL;
|
ThreadNode *pre = NULL;
|
||||||
```
|
```
|
||||||
|
|
||||||
Then it is very simple. The predecessor of this node is obviously `pre`.
|
Then it is very simple. The predecessor of this node is obviously `pre`.
|
||||||
|
|
||||||
```
|
```c
|
||||||
void visit(ThreadNode p){
|
void visit(ThreadNode p){
|
||||||
if (p->lchild == NULL) { // If the left child of this node is empty
|
if (p->lchild == NULL) { // If the left child of this node is empty
|
||||||
p->lchild = pre; // Point the left pointer to pre, indicating that the predecessor of p is the node pointed to by pre
|
p->lchild = pre; // Point the left pointer to pre, indicating that the predecessor of p is the node pointed to by pre
|
||||||
|
|
@ -160,7 +160,7 @@ How do we find the successor?
|
||||||
|
|
||||||
It is very simple. Since the predecessor of `p` is `pre`, then the successor of `pre` must be `p`. Therefore:
|
It is very simple. Since the predecessor of `p` is `pre`, then the successor of `pre` must be `p`. Therefore:
|
||||||
|
|
||||||
```
|
```c
|
||||||
void visit(ThreadNode p){
|
void visit(ThreadNode p){
|
||||||
if (p->lchild == NULL) {
|
if (p->lchild == NULL) {
|
||||||
p->lchild = pre;
|
p->lchild = pre;
|
||||||
|
|
@ -180,7 +180,7 @@ Obviously, both `pre` and `p` now point to $C$. We can directly set the `rtag` o
|
||||||
|
|
||||||
The recursive code is very similar to ordinary preorder traversal, but there is one point that requires attention. When we visit the left child of a node, we need to check whether that left child is already a defined thread pointer.
|
The recursive code is very similar to ordinary preorder traversal, but there is one point that requires attention. When we visit the left child of a node, we need to check whether that left child is already a defined thread pointer.
|
||||||
|
|
||||||
```
|
```c
|
||||||
void PreThread(ThreadTree T) {
|
void PreThread(ThreadTree T) {
|
||||||
if (T != NULL) {
|
if (T != NULL) {
|
||||||
visit(T); // Visit T. If the left child of T is NULL, point it to its predecessor. If the right child of T's predecessor is NULL, point the right pointer of pre to T.
|
visit(T); // Visit T. If the left child of T is NULL, point it to its predecessor. If the right child of T's predecessor is NULL, point the right pointer of pre to T.
|
||||||
|
|
@ -192,7 +192,7 @@ void PreThread(ThreadTree T) {
|
||||||
|
|
||||||
Putting the code together gives us:
|
Putting the code together gives us:
|
||||||
|
|
||||||
```
|
```c
|
||||||
typedef struct ThreadNode {
|
typedef struct ThreadNode {
|
||||||
ElemType data;
|
ElemType data;
|
||||||
struct ThreadNode *lchild, *rchild;
|
struct ThreadNode *lchild, *rchild;
|
||||||
|
|
@ -240,7 +240,7 @@ The underlying idea is actually very similar. Only the visiting order differs, w
|
||||||
|
|
||||||
**Inorder threading**:
|
**Inorder threading**:
|
||||||
|
|
||||||
```
|
```c
|
||||||
void InThread(ThreadTree T){
|
void InThread(ThreadTree T){
|
||||||
if (T!=NULL){
|
if (T!=NULL){
|
||||||
InThread(T->lchild);
|
InThread(T->lchild);
|
||||||
|
|
@ -252,7 +252,7 @@ void InThread(ThreadTree T){
|
||||||
|
|
||||||
**Postorder threading**:
|
**Postorder threading**:
|
||||||
|
|
||||||
```
|
```c
|
||||||
void PostThread(ThreadTree T) {
|
void PostThread(ThreadTree T) {
|
||||||
if (T!=NULL) {
|
if (T!=NULL) {
|
||||||
PostThread(T->lchild);
|
PostThread(T->lchild);
|
||||||
|
|
@ -308,7 +308,7 @@ What? You are asking about the right node? If the root node does not exist, how
|
||||||
|
|
||||||
Thus:
|
Thus:
|
||||||
|
|
||||||
```
|
```c
|
||||||
ThreadNode *FirstNode(ThreadNode *p) { // This is the second step; the first step is the function below
|
ThreadNode *FirstNode(ThreadNode *p) { // This is the second step; the first step is the function below
|
||||||
while(p->ltag==0) p = p->lchild; // Keep going deeper into the left subtree until the leftmost node is found—in other words, a node without a left child
|
while(p->ltag==0) p = p->lchild; // Keep going deeper into the left subtree until the leftmost node is found—in other words, a node without a left child
|
||||||
return p; // This node is the successor we are looking for
|
return p; // This node is the successor we are looking for
|
||||||
|
|
@ -338,7 +338,7 @@ $$
|
||||||
|
|
||||||
Similarly, our approach is to find the rightmost node in the left subtree:
|
Similarly, our approach is to find the rightmost node in the left subtree:
|
||||||
|
|
||||||
```
|
```c
|
||||||
ThreadNode *LastNode(ThreadNode *p){ // This is the second step; the first step is the function below
|
ThreadNode *LastNode(ThreadNode *p){ // This is the second step; the first step is the function below
|
||||||
while(p->rtag==0) p = p->rchild; // Keep going deeper into the right subtree until the rightmost node is found—in other words, a node without a right child
|
while(p->rtag==0) p = p->rchild; // Keep going deeper into the right subtree until the rightmost node is found—in other words, a node without a right child
|
||||||
return p;
|
return p;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue