Time: November 9, 2021

Author: atavistic ape

Topic set: data structure and algorithm topic set (Chinese)

Title: isomorphism of 7-3 trees (25 points)

# 1. Foreword

I actually solved a tree problem!!!

I am very excited!!!

I'm going to strike while the iron is hot and record my ideas here. If there are similarities, it's purely accidental.

# 2. Title

## Input sample 1 (corresponding to the tree in the figure)

8 A 1 2 B 3 4 C 5 - D - - E 6 - G 7 - F - - H - - 8 G - 4 B 7 6 F - - A 5 1 H - - C 0 - D - - E 2 -

## Output sample 1

Yes

## Input sample 2

8 B 5 7 F - - A 0 3 C 6 - H - - D - - G 4 - E 1 - 8 D 6 - B 5 - E - - H - - C 0 2 G - 3 F - - A 1 4

## Output sample 2

No

# 3. Code

#include<stdio.h> typedef struct node{ int id; char c; struct node *left; struct node *right; } P; int countChildren(P *pa); int answer(P *pa, P *pb); int main(){ // Define variables P pa[10], pb[10]; P *rootA, *rootB; int flagA[10] = {}, flagB[10] = {}; int m, n, i; char temp; // Control input 1 scanf("%d", &n); for(i=0; i<n; i++){ pa[i].id = i; // Left node scanf("\n%c %c ", &pa[i].c, &temp); if(isdigit(temp)){ pa[i].left = &pa[temp-'0']; flagA[temp-'0'] = 1; } else { pa[i].left = NULL; } // Right node scanf("%c", &temp); if(isdigit(temp)){ pa[i].right = &pa[temp-'0']; flagA[temp-'0'] = 1; } else { pa[i].right = NULL; } } // Control input 2 scanf("%d", &m); for(i=0; i<m; i++){ pb[i].id = i; // Left node scanf("\n%c %c ", &pb[i].c, &temp); if(isdigit(temp)){ pb[i].left = &pb[temp-'0']; flagB[temp-'0'] = 1; } else { pb[i].left = NULL; } // Right node scanf("%c", &temp); if(isdigit(temp)){ pb[i].right = &pb[temp-'0']; flagB[temp-'0'] = 1; } else { pb[i].right = NULL; } } // ---------------------------------------------------------------- // Exclude obvious different composition trees if(n != m){ printf("No"); return 0; } if(n == 1){ if(pa[0].c != pb[0].c){ printf("No"); } else { printf("Yes"); } return 0; } if(n == 0){ printf("Yes"); return 0; } // Find the root node of two trees for(i=0; i<n; i++){ if(flagA[i] == 0){ rootA = &pa[i]; } if(flagB[i] == 0){ rootB = &pb[i]; } } // Test: test whether the root node is correct // printf("rootA: %d %c\n", rootA->id, rootA->c); // printf("rootB: %d %c\n", rootB->id, rootB->c); // true // Determine whether the root node is the same if(rootA->c != rootB->c){ printf("No"); return 0; } if(answer(rootA, rootB) == 0){ printf("No"); } else { printf("Yes"); } return 0; } // This method determines how many children the node has int countChildren(P *pa){ int count = 2; if(pa->left == NULL) count--; if(pa->right == NULL) count--; if(count == 2){ return 2; } else if(count == 0){ return 0; } else if(pa->left != NULL){ return -1; } else if(pa->right != NULL){ return 1; } } // This method recursively judges whether the children of each node of the two trees are the same int answer(P *pa, P *pb){ int countA = countChildren(pa); int countB = countChildren(pb); P *tempA, *tempB; char pal, par, pbl, pbr; // The number of children is different if(abs(countA) != abs(countB)){ return 0; } // All are leaf nodes. Because it has been judged that the two nodes are the same before sending in, 1 is returned if(countA == 0 && countB == 0){ return 1; } // If there is only one child, the characters saved by the two children must be the same if(countA != 2){ if(countA>0){ tempA = pa->right; } else { tempA = pa->left; } if(countB>0){ tempB = pb->right; } else { tempB = pb->left; } // printf("\n%c %c\n", tempA->c, tempB->c); // Note: if you return, the program is over, so you won't enter the situation of two children from here if(tempA->c == tempB->c){ return answer(tempA, tempB); } else { return 0; } } // The situation of two children pal = pa->left->c; par = pa->right->c; pbl = pb->left->c; pbr = pb->right->c; // printf("\n%c %c %c %c\n", pal, par, pbl, pbr); // note: there should not be the same situation for left and right children, right if((pal == pbl || pal == pbr)&&(par == pbl || par == pbr)){ if(pal == pbl){ return answer(pa->left, pb->left) && answer(pa->right, pb->right); } else { return answer(pa->left, pb->right) && answer(pa->right, pb->left); } } else { return 0; } }

Ho, I think the code is too long. Does anyone really see it (←←)

# 4. Thinking process

## ① Find root node

Regardless of the others, after reading the input, I found that its root nodes were not given out in order, which really persuaded me to retreat

Then I noticed that the root node must not appear in the last two numbers in each row, so I used a very stupid method to find the root node: record the last two columns of numbers, and the number that does not appear is the root node.

It turns out that this method works well~

## ② Implement check isomorphism

After realizing the input, start thinking about how to realize the method of judging the isomorphism of two trees.

### a. Look for ways to check that two children of two nodes are the same but in different order

The biggest feature of isomorphism is that the two children at the same node of two trees are the same, but the order is different. However, a node has two children. It is a little windy to judge whether the two children at two nodes are the same.

- First, write four variables on the paper: pal, par, PBL and PBR, representing four children respectively;
- Then the same discriminant for two children of two nodes is derived: (PAL = = PBL | pal = = PBR) & & (PAR = = PBL | par = = PBR);
- Two nodes satisfying the discriminant enter the next recursion field:
- if(pal == pbl) return answer(pa->left, pb->left) && answer(pa->right, pb->right);
- else return answer(pa->left, pb->right) && answer(pa->right, pb->left);

Here I explain why I use recursion, because I can't write with while... Well, really, sometimes I think recursion is simpler than while. This is definitely not my own idea.

But you don't think so when you implement recursion.

In addition, I'd like to think that the characters in two children at a certain byte point are the same, but from the perspective of common sense, the problem maker should not be so crazy... Right?? For the time being.

It turns out that I really think too much. It's just me.

### b. Eliminate obvious wrong answers

When you continue to write down, you should start thinking about answering questions.

After reading the question again, I found that the question did not say that the nodes of the two trees could not be 0, so I looked carefully again and found that the question really did not say that the nodes of the two trees were not 0, emmm. Let's write the output "No". After submitting it again, I found that there was a test point specifically for this situation, and the answer was "Yes". I was speechless.

When there is only one node, the problem is very simple.

If the number of nodes of the two trees is different, the two trees must be different. Therefore, m must be defined to control the input of the second lesson tree. It should be noted that if the number of nodes in the second tree is input and then judged, output and return immediately, but the node in the second tree is not received, pta will make a mistake because it does not fully receive the data given by it. This is a lesson from another problem.

Yes, I've even made such mistakes

In addition, in the case of multiple nodes, the characters saved by the root node are obviously different, which solves the initialization problem of entering recursion for the first time.

### c. Implement the main content of recursive methods

I couldn't think of other obvious mistakes for a moment, so I turned back and continued to work on the topic.

Because the code is written recursively, you should plan how to use recursion:

- Provision: the characters saved by the two nodes entering recursion are the same, that is, the two nodes are isomorphic, regardless of the child.
- 2, Recursively judge whether the children of two nodes save the same characters, that is, judge the isomorphism of children.
- 3, return is... emmm... I couldn't figure out how to describe this for a while, so pass.

In fact, there are still uncertainties in the simply written provisions, but I can't think of many at a time, so I first moved the judgment code of two nodes and two children into the recursive method. The method name is answer, because I can't think of a good name for a while. Even if I write an answer, I have to spell Baidu.

Writing, I suddenly thought that a node may not have two children, or may not have children, or even the other child is not a node at all (but NULL). For a time, I felt that the difficulty of writing recursion soared and persuaded * 2.

So I sorted out what my recursion was writing and recorded three branches:

- One child per node;
- Two children per node;
- Node has no children;

Nonsense literature hammer.

Two children pass.

When the node has only one child, first judge which child is not a child (when recursive codeword is in progress), that is, the other child is NULL.

Therefore, the previously written method to judge whether the characters saved by two nodes are the same is changed to judge how many children a node has. For convenience, when the left child of the node is NULL, it returns 1, and when the right child is NULL, it returns - 1, which is the horizontal axis of reference, left negative and right positive. As a result, it was used incorrectly later, and the error correction time was + 20min. The method name is countChildren.

countA = countChildren(pa), pb is the same as the processing.

When you really make a judgment, you even think about char Tempa = counta > 0? Pa - > right - > C: the distorted writing of pa - > right - > C has proved that code integration is too troublesome, so it is changed to P Tempa = counta > 0? Pa - > right: pa - > right. I found that the compiler did not prompt me in time when I wrote right. I was surprised that it was unreliable. Finally, I changed it to a simple if statement.

Actually, plus ( ) () () no problem.

### d. Perfect recursive method and main method

When I finished writing the case of only one child, I found that there was a "node without children" waiting for me. I was tired and didn't love it.

However, the code has been completed to this step. Do you want to shrink back? No.

When writing about the case of only one child, I thought that if the number of children of two nodes is different, the two nodes are also different in structure, so I added this judgment.

There is also a small mistake here, because countChildren returns 1 and - 1. You have to set an abs for it to compare. Error correction often takes + 20min.

It is simple for a node to have no children, because it stipulates that the two nodes entering recursion are isomorphic and directly return 1.

At this point, the recursive method ends.

## ③ Final carding procedure

After checking the main method, the main method is over.

Because the code was written carefully, only one of the six monitoring points was wrong, or because the empty tree returned Yes or No. to be honest, I was a little happy. If you make a mistake here, you'll collapse.

Instead, when testing the case, correct the error for a long time, speechless, calm and calm, and hold on to the ━ (~(

# 5. Postscript

This is not the first time to do a 25 point question, but it is the first time to do the right tree, which has a great sense of achievement.

So far, we can't even deduce the structure of tree according to preorder traversal and middle order traversal.

If you feel it, please share it in the comment area.

Even if not, after all, I don't read such smelly and long Doges

Thousands of words have no ink to fall. Don't pay attention. Goodbye.

Black history + 1