Data structure sample code and its explanation - recursion and tree

Tree

Many topics of trees contain recursive ideas

recursion

Recursion includes 递归边界and递归式

That is: hand down, return up

Features of recursive writing:The code is shorter to write, but the time complexity is higher

01 Use recursion to find the factorial of n.
int Func(int n) {
    
    
	if (n == 0) {
    
    
		return 1;
	}
	else {
    
    
		return n * Func(n - 1);
	}
}
02 The Fibonacci sequence is a sequence that satisfies F(0)=1, F(1)=1, F(n)=F(n-1)+F(n-2)(n≥2). The first few items are 1, 1, 2, 3, 5, 8, 13, 21…. Write a program to find the nth term of the Fibonacci sequence.
int Fbnq(int n) {
    
    
	if (n == 0||n == 1) {
    
    
		return 1;
	}
	else {
    
    
		return Fbnq(n - 1) + Fbnq(n - 2);
	}
}

Tree

Binary tree chain storage structure definition.

typedef struct BiTNode {
    
    
	int data;
	struct BiTNode* lchild, * rchild;
}BiTNode,*BiTree;
01 Binary tree pre-order recursive traversal algorithm

Pre-order recursive traversal: around the root

void PreOrder(BiTree T) {
    
    
	if (T == NULL) {
    
    //递归边界
		return;
	}
	else {
    
    
		printf("%d", T->data);//打印此结点数据域中的数据值
		PreOrder(T->lchild);//递归遍历左子树
		PreOrder(T->rchild);//递归遍历右子树
	}
}

The easy way to write it is as follows:

//简便
void PreOrder(BiTree T) {
    
    
	if (T != NULL) {
    
    
		printf("%d", T->data);
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}

Therefore, some codes are difficult to understand because they hide the recursive boundary, making it difficult to understand easily.

02 Binary tree in-order recursive traversal algorithm

Inorder recursive traversal: left root right

void InOrder(BiTree T) {
    
    
	if (T != NULL) {
    
    //若所处理的结点不为空
		InOrder(T->lchild);//递归遍历左子树
		printf("%d", T->data);//打印此结点数据域中的数据值
		InOrder(T->rchild);//递归遍历右子树
	}
}
03 Binary tree post-order recursive traversal algorithm

Post-order recursive traversal: left and right roots

void PostOrder(BiTree T) {
    
    
	if (T != NULL) {
    
    
		PostOrder(T->lchild);
		PostOrder(T->rchild);
		printf("%d", T->data);
	}
}
04 In a binary tree with a binary linked list as the storage structure, check whether the node whose data field value is equal to the key exists, and if so, point the pointer q to the node, assuming that the node data field is int type. (The node values ​​​​in the binary tree are all different)
  1. Since the pointer q may change, you need to add &; starting from the variable identifier and looking from right to left, the closest to the identifier is the essential type of the variable, and then to the left is the further modification of the variable type, in C++ The asterisk represents a pointer, & represents a reference, and *& represents a pointer reference;
  2. BiTNode*& q: The left side of the identifier q is &, indicating that q is a reference variable, and then to the left is *, so q is a reference to a pointer variable, and to the left is BiTNode, so q is aA reference to a pointer of type BiTNode
  3. Rewrite the preorder recursive traversal here.
void Search(BiTree T, BiTNode*& q, int key) {
    
    
	if(T!=NULL){
    
    
		if (T->data == key) {
    
    
			q = T;//若为 key 则指针 q 指向该结点
		}
		else {
    
    
			Search(T->lchild, q, key);
			Search(T->rchild, q, key);
		}
	}
}
05 Assuming that the binary tree is stored in the form of a binary linked list, design an algorithm to find the value of the kth (1≤k≤number of nodes in the binary tree) node in the preorder traversal sequence.
  1. A counting variable is required. Because it is recursive, each call is equivalent to calling the function again, so the counting variable needs to be a global variable;
  2. This question rewrites the pre-order recursive traversal. Since n=0 at the beginning, when entering if, it will add itself first, and then judge;
int n = 0;//定义全局变量 n 进行计数
int Search_k(BiTree T, int k) {
    
    
	if (T != NULL) {
    
    //改写先序递归遍历
		n++;//更新变量 n,记录现在访问的是第几个结点
		if (n == k) {
    
    //若 n 等于 k 则直接打印访问结点的数据值并结束此次递归
			printf("%d", T->data);
			return T->data;
		}
		else {
    
    
			Search_k(T->lchild, k);
			Search_k(T->rchild, k);
		}
	}
}
06 Use recursion to calculate the number of all nodes in the binary tree.

Law one

​ Take advantage of recursion

int n = 0;
void calc(BiTree T) {
    
    
	if (T == NULL) {
    
    
		return;}
	else {
    
    
		n++;
		calc(T->lchild);
		calc(T->rchild);
	}
}
int n=0;//定义全局变量 n 用来计数
void calc(BiTree T){
    
    
	if(T!=NULL){
    
    //改写先序递归遍历
		n++;//将先序遍历中访问结点代码改写为计数代码
		calc(T->lchild);//递归遍历左子树
		calc(T->rchild);//递归遍历右子树
	}
}

law two

  1. Pay attention to the second idea: If you calculate the number of all nodes in the tree rooted at a certain node, you can first calculate the number of all nodes whose root is the left node of the node, and then calculate the right node of the node Points are all the numbers of roots, and finally add 1 (the node itself) to get the number of all nodes ; then continue to split the problem.
  2. Define n1 and n2 variables to receive the number of nodes in the left subtree and right subtree. This variable is a local variable that records the number of nodes in the left subtree and right subtree of the recursive function.
  3. Because it is recursive, when reaching the leaf node, continue to go down, the left subtree is empty, return 0, so n1=0, the right subtree is empty, return 0, so n2=0, so the leaf node returns upward When it is n1 + n2 + 1=1. Then go up in turn to get the number of nodes.
int Count(BiTree T) {
    
    
	int n1, n2;//定义 n1 和 n2 分别用于接收左右子树结点个数
	if (T == NULL) {
    
    
		return 0;
	}
	else {
    
    
		n1 = Count(T->lchild);//递归求解左子树中结点个数,结果 n1 接收
		n2 = Count(T->rchild);
		return n1 + n2 + 1;//再加根结点
	}
}

The code of method 2 is 求二叉树的高度、求叶子结点的个数、求单/双分支结点的个数the algorithm idea, when recursing, try to draw the left and right empty subtrees of the leaf nodes.

07 Use recursion to calculate the number of all leaf nodes in the binary tree.

Law one

  1. rewrite preorder recursive traversal
//法一
int n = 0;
void Countleaves(BiTree T) {
    
    
	if (T != NULL) {
    
    
        //所处理结点是否为叶子结点
		if (T->lchild == NULL && T->rchild == NULL) {
    
    
			n++;//若遍历结点是叶子结点则计数
		}
		Countleaves(T->lchild);//递归遍历左子树
		Countleaves(T->rchild);

	}
}

law two

  1. Recursive boundary, the tree is empty, indicating that there is no leaf node, the node is a leaf node, return 1
  2. The final return is n1+n2
//法二
int Countl(BiTree T) {
    
    
	int n1, n2;//接受左右子树的叶子结点个数
	if (T == NULL) {
    
    
		return 0;
	}
	else if (T->lchild == NULL && T->rchild == NULL) {
    
    
		return 1;
	}
	else {
    
    
		n1 = Countl(T->lchild);//递归求解左子树中叶子结点的个数,结果 n1 接收
		n2 = Countl(T->rchild);
		return n1 + n2;
	}
}
08 (Question 1) Use recursion to calculate the number of all double-branch nodes in the binary tree.
  1. Classification and Treatment of Double-Branch Nodes

① Double branch n1+n2+1, look at the double branch of the left subtree, the double branch of the right subtree, plus itself;

②Single branch n1+n2, look at the double branch of the left subtree and the double branch of the right subtree;

③ Leaf node n1+n2, look at the double branch of the left subtree and the double branch of the right subtree;

④ NULL 0 (recursion boundary)

The +1 operation of the above double branch is added this time, so +1 is required

  1. Due to whether it is a double branch or a single branch, the recursive change is caused.
//(题一)利用递归计算二叉树中所有双分支结点个数。
int Count(BiTree T) {
    
    
	int n1, n2;
	if (T == NULL) {
    
    //递归边界
		return 0;
	}
	else if (T->lchild != NULL && T->rchild != NULL) {
    
    
		n1 = Count(T->lchild);//递归求解左子树双分支结点个数,结果用 n1 接收 
		n2 = Count(T->rchild);
		return n1 + n2 + 1;
	}
	else {
    
    若不为空树,根结点也不为双分支结点,也就是叶子结点和单分支结点的情况
		n1 = Count(T->lchild);
		n2 = Count(T->rchild);
		return n1 + n2;
	}
}
09 (Question 2) Use recursion to calculate the number of all single-branch nodes in the binary tree.
  1. Classification and Treatment of Single-Branch Nodes

① Double branch n1+n2 Look at the single branch of the left subtree and the single branch of the right subtree;

②Single branch (with a left child but no right child or with a right child but no left child) n1+n2+1 Look at the single branch of the left subtree, the single branch of the right subtree, plus itself;

③The leaf node n1+n2 looks at the single branch of the left subtree and the single branch of the right subtree;

④NULL 0

  1. Merge ① and ③ above into else.
int Count_Simple_Node(BiTree T) {
    
    
	int n1, n2;
	if (T == NULL) {
    
    
		return 0;
	}
	if ((T->lchild && T->rchild == NULL) || (T->lchild == NULL && T->rchild)) {
    
    
		n1 = Count_Simple_Node(T->lchild);//递归求解左子树单分支结点个数,结果用 n1 接收
		n2 = Count_Simple_Node(T->rchild);
		return n1 + n2 + 1;
	}
	else {
    
    
		n1 = Count_Simple_Node(T->lchild);//递归求解左子树单分支结点个数,结果用 n1 接收
		n2 = Count_Simple_Node(T->rchild);
		return n1 + n2;
	}
}

10 Use recursion to calculate the depth of the binary tree.
  1. Define two variables to receive the depth of the left and right subtrees;
  2. 判断左右子树哪个更深,若左子树更深则树总深度为左子树深度+1(根也算一层) ,若右子树更深则树总深度为右子树深度+1(根也算一层) , 两棵子树高相等,既可以左子树+1,也可以右子树+1,这里的1就是根所在的一层,所以+1,可以自己模拟一下。
int Depth(BiTree T) {
    
    
	int ldep;
	int rdep;
	if (T == NULL) {
    
    
		return 0;
	}
	ldep = Depth(T->lchild);//递归求解左子树深度,结果用 ldep 接收
	rdep = Depth(T->rchild);
    //判断左右子树哪个更高,高的树加上根节点那一层
	if (ldep > rdep) {
    
    
		return ldep + 1;
	}
	else {
    
    
		return rdep + 1;
	}
}
11 Suppose tree B is a binary tree stored in the form of binary linked list, and write a function to exchange the left and right subtrees of all nodes in tree B.
  1. Using recursion, rewrite the pre-order recursive traversal, root left and right, and exchange its left and right children each time.
void Swap(BiTree &B){
    
    
	if(B!=NULL){
    
    
		BiTNode *temp=B->lchild;//定义 temp 辅助指针,辅助 B 左右子树交换,交换(指针域变换)
		B->lchild=B->rchild;
		B->rchild=temp;
		Swap(B->lchild);//递归处理左子树
		Swap(B->rchild);//递归处理右子树
	}
}
12 Assuming that the binary tree uses a binary linked list storage structure, design an algorithm to find the level number of the node whose value is x in the binary tree T.
  1. To find a node, to traverse it, use pre-order traversal here, and pass a level parameter here, representing the current layer of the root;
  2. This question is unusual
void Search_x_level(BiTree T, int x, int level) {
    
    
	//level是当前根节点所在的层次
	if (T != NULL) {
    
    
		if (T->data == x) {
    
    
			printf("x所处的层数为%d", level);
		}
		Search_x_level(T->lchild, x, level + 1);
		Search_x_level(T->lchild, x, level + 1);
	}
}
void Func(BiTree T, int x) {
    
    
	Search_x_level(T, x, 1);//初始时根所在层次为 1 
}

​ Idea 2: first layer the nodes, for example, node 1 is on the first layer, nodes 2 and 3 are on the second layer, nodes 4, 5, 6, and 7 are on the third layer, and then the search value is where x is levels. This idea feels a bit cumbersome

13 Please write a binary tree level traversal algorithm.
  1. Since hierarchical traversal is traversal by layer, nodes will be jumped, and assistance is required**queue** (first in first out)

① Put the root node into the team first;

② Dequeue, print;

③ lchild joins the team;

④rchild joins the team;

②③④Circulation

void LevelOrder(BiTree T) {
    
    
	Queue Q;//定义一个队列 Q
	InitQueue(Q);//初始化队列 Q
	BiTNode* p = T;//定义一个遍历指针 p,初始时指向根结点
	EnQueue(Q, p);//将根结点入队
	while (!IsEmpty(Q)) {
    
    //队列不为空则继续循环
		DeQueue(Q, p);//出队,并让 p 指向出队结点
		printf("%d", p->data);//打印出队结点数据域中的数据
		if (p->lchild != NULL) {
    
    
			EnQueue(Q, p->lchild);//若出队结点有左孩子,则让其左孩子入队
		}
		if (p->rchild != NULL) {
    
    
			EnQueue(Q, p->rchild);//若出队结点有右孩子,则让其右孩子入队
		}
	}
}
14 Try to write a bottom-up, right-to-left hierarchical traversal algorithm for a binary tree.
  1. Layer order traversal is from top to bottom, from left to right, that is, reverse layer order traversal. , of course, you still need to use the queue, just put it on the stack first, and then pop it out and print it in turn at the end.
  2. Print: Pop out the stack one by one and print (the author just started using the for loop, indicating that he is still not familiar with the basic operations of the stack and queue)
  3. In this question, the ordering of hierarchical traversal in the queue is from top to bottom, from left to right, but the title requires the opposite, so an additional operation is made in the middle of the guess to reverse the order, and the stack just happens to have the opposite input and output ( first in last out, last in first out), so you canPush each dequeue node onto the stack, and traverse the stack at the end
  4. The code of this question is similar to the previous question, except that it is printed after leaving the queue, but it is pushed onto the stack, and the queue is empty at the end. After processing each layer of nodes, the stack is traversed and printed.
  5. Note that the print operation needs to be dequeued or popped, and then printed.
void ReverseLevelOrder(BiTree T) {
    
    
	Queue Q;//定义队列 Q
	Stack S;//定义栈 S
	InitQueue(Q);//初始化队列 Q
	InitStack(S);//初始化栈 S
	BiTNode* p = T;//定义遍历指针 p,初始时指向根结点
	EnQueue(Q, p);//根结点入队
	while (!IsEmpty(Q)) {
    
    
		DeQueue(Q, p);
		Push(S, p);//将出队结点压入栈 S 中
		if (p->lchild) {
    
    
			EnQueue(Q, p->lchild);
		}
		if (p->rchild) {
    
    
			EnQueue(Q, p->rchild);
		}
	}
	//打印操作
	while (!IsEmpty(S)) {
    
    //栈不为空则继续循环
		Pop(S, p);//出栈,并让 p 指向出栈结点
		printf("%d", p->data);
	}
}
15 The binary tree is stored in the form of a binary linked list, write a method to judge whether a given binary tree iscomplete binary treealgorithm.

⭐⭐⭐⭐⭐

  1. First of all, we must know what a complete binary tree is. Except for the last layer of a complete binary tree, the nodes of other layers are full, and the nodes of the last layer are arranged as far as possible to the left. In simple terms, a complete binary tree is a compact and balanced binary tree.
  2. The idea of ​​this algorithm is the same as that of layer order traversal, define a traversal pointer, point to the root node, and then enter the queue. If the queue is not empty, exit the queue, if there is a left child, add the left child to the queue, if there is a right child, add the right child to the queue, and repeat;
  3. When judging a complete binary tree, theNULL is also enqueued, because the complete binary tree nodes are continuous in the queue, and there is no NULL in the middle. If it is not a complete binary tree, in the queue, there will be nodes with values ​​behind the NULL nodes, resulting in no nodes in the queue. continuous. Through this, we can judge whether it is a complete binary tree, that is, when we traverse to NULL nodes, we can dequeue all the nodes in the queue. If non-empty nodes exist, it means that it is not a complete binary tree.
  4. You can draw a tree and queue to simulate the process.
int IsComplete(BiTree T) {
    
    
	if (T == NULL) {
    
    //空树是完全二叉树
		return 1;
	}
	Queue Q;//定义队列
	InitQueue(Q);
	BiTNode* p = T;//定义遍历指针p初始时指向根结点
	EnQueue(Q, p);//让根结点入队
	while (!IsEmpty(Q)) {
    
    
		DeQueue(Q, p);//出队并让 p 指向出队结点
		if (p != NULL) {
    
    //若 p 不为空
			EnQueue(Q, p->lchild);//让其左孩子入队(左孩子为空则入队 NULL)
			EnQueue(Q, p->rchild);//让其右孩子入队(右孩子为空则入队 NULL)
		}
		else {
    
    //p是空结点,队列中其后面的所有结点均应该是空结点,否则不符合完全二叉树
			while (!IsEmpty(Q)) {
    
    //队列不为空则需继续循环
				DeQueue(Q, p);//出队并让 p 指向出队结点
				if (p != NULL) {
    
    
					return 0;//若后续还有结点则不是完全二叉树
				}
			}
		}
	}
	return 1;//若队列中剩余数据都为 NULL 则证明是完全二叉树
}
16 The binary tree is stored in the form of a binary linked list, and an algorithm is designed to complete it: for each node whose element value is x in the tree, delete the subtree rooted at it and release the corresponding space.
  1. ①查找到元素为x的结点②如何删除以它为根的树, delete the node from bottom to top, because if the root node is deleted from top to bottom, the position of its left and right child nodes cannot be located;
  2. After finding the node whose element is x, it is necessary to disconnect the link between x and its parent node. Here, layer-order traversal is used to search layer by layer;
  3. The two cases where the tree is empty and the value of the root node of the tree is x are special cases and need to be written separately.
  4. In the normal search process, first define a queue, then enter the root node of the tree into the queue, and then perform a loop (judging whether the queue is empty, if it is not empty, exit the queue, the left child enters the queue, and the right child enters the queue), the left child During the enqueue and right child enqueue process, if its value is x, directly call the DeleteTree function, and finally set its pointer field to empty, see the code for details;

Delete the tree rooted at T from bottom to top

  1. Rewrite post-order recursive traversal, left and right roots, that is, first find the left subtree, then find the right subtree, and finally process the root, and finally recurse down, the root node is the last to be deleted.
//从下往上删除以T为根节点的树
void DeleteTree(BiTree& T) {
    
    
	if (T != NULL) {
    
    
		DeleteTree(T->lchild);
		DeleteTree(T->rchild);
		free(T);//释放结点空间
	}
}

Find the node whose element is x

  1. When the root node of the tree is the x to be searched, directly call the DeleteTree() function, and write a return at the end, indicating that the operation can be ended.
  2. Ordinary layer order traversal is, if the left and right subtrees are not empty, enqueue the left and right subtrees, and what is needed here is, if the left and right subtrees are not empty, judge whether its value is equal to x, if it is equal, it means that the search has been found , needs to be deleted, call the DeleteTree() function, and at this time, the left and right pointer fields of the node need to be empty; if it is not equal to x, if it is not found, it is the same as the normal operation.
//查找元素为x的结点
void SearchX(BiTree& T, int x) {
    
    
	if (T == NULL) {
    
    
		return;
	}
	if (T->data == x) {
    
    //删除整棵树也是这里的特殊情况,因为不需要做任何遍历查找
		DeleteTree(T);
        return;//函数执行结束
	}
	Queue Q;
	InitQueue(Q);
	BiTNode* p = T;
	EnQueue(Q, p);//入队
	while (!IsEmpty(Q)) {
    
    
		DeQueue(Q, p);//出队并让 p 指向出队结点
		if (p->lchild != NULL) {
    
    //左孩子判断
			if (p->lchild->data == x) {
    
    //如果p的左孩子的值=x,说明查找到了,删除
				DeleteTree(p->lchild);
				p->lchild = NULL;//指针域置空,因为删除函数只是对结点的删除
			}
			else {
    
    
				EnQueue(Q, p->lchild);//如果p的左孩子的值不是x,正常进行层次遍历
			}
		}
		if (p->rchild != NULL) {
    
    //右孩子判断
			if (p->rchild->data == x) {
    
    //如果p的左孩子的值=x,说明查找到了,删除
				DeleteTree(p->rchild);
				p->rchild = NULL;//指针域置空,因为删除函数只是对结点的删除
			}
			else {
    
    
				EnQueue(Q, p->rchild);//如果p的左孩子的值不是x,正常进行层次遍历
			}
		}
	}
}
17 The binary tree uses a binary linked list storage structure, and a non-recursive algorithm is designed to find the height of the binary tree.
  1. Since the height of the binary tree is non-recursively calculated, level traversal is required, and a variable h is defined. Every time a layer is traversed, h changes accordingly;

  2. How to judge that a certain layer has been traversed: define the last variable: point to the last node of each layer, if the last node of each layer is processed, this layer is also processed, and h can be changed;

  3. The previous topic was the basic operation of the call queue, but this time it will not work. This time the research is more detailed and needs to be changed; during the previous initialization, both front and rear were 0.

  4. But if the above method is used here, the rear will point to the last position of each node, which is equivalent to a stagger, and the last variable defined for the height of the binary tree needs to be used together with the rear, so here we initialize the front and rear Both point to -1. When entering the team, first rear+1, and then assign a value to join the team. At this time, the rear and the node are not staggered.

  5. Here to judge 队列whether ==== is empty is front<rear, to judge whether the last node of each layer is front==last, here initially, last=0, because the root node enters the queue first, its subscript is also 0, and The root node is also the last element of the first layer, which ensures that after the root node enters the team for the first time, it enters the loop and the root node leaves the team. At this time, the front is also 0, and the last is also 0, so that h++ and last are updated.

int Depth(BiTree T) {
    
    
	if (T == NULL) {
    
    
		return 0;
	}
	int h = 0;//变量 h 用来记录高度
	int last = 0;//变量 last 用来记录每一层最右边结点位置 
	BiTNode* Q[MaxSize];//定义队列 Q
	int front = -1, rear = -1;//定义队头指针和队尾指针
	BiTNode* p = T;//定义遍历指针p初始时指向根结点
	Q[++rear] = p;//根结点入队 
	while (front < rear) {
    
    //队列不为空则继续循环 
		p = Q[++front];//出队,p 指向出队结点 
		if (p->lchild) {
    
    //若此结点有左孩子则让其左孩子入队 
			Q[++rear] = p->lchild;
		}
		if (p->rchild){
    
    //若此结点有右孩子则让其右孩子入队 
			Q[++rear] = p->rchild;
		}
		if (front == last) {
    
    //若二叉树其中一层的最右边结点出队 
			h++;//让高度加一 
			last = rear;//更新 last,使其指向下一层最右边结点位置 
		}
	}
	return h;//返回二叉树的高度 
}
18 Assuming that the binary tree uses a binary linked list storage structure, design an algorithm to find the width of a given binary tree. (Width is the number of nodes in the layer with the largest number of nodes in the tree)
  1. Hierarchical traversal of binary trees;

  2. Here, when recording which layer a node belongs to, define a new array to record the number of layers where each node is located;

  3. After traversing the layers, the obtained array is a record containing the number of layers of each node. You only need to traverse the array to find which layer has the most number, so as to find the width and the corresponding number of layers.

  4. For example: suppose the node element is

    ​ 1

    ​ 3 4

    ​ 5 8 9 4

    6

    Then the array is 1 2 2 3 3 3 3 4, indicating that the width is 4, because the number of nodes in the third layer is 4.

int Width(BiTree T) {
    
    
	if (T == NULL)//若为空树则宽度为 0 
		return 0;
	BiTNode* Q[MaxSize];//定义队列 Q 
	int front = 0, rear = 0;//定义队头指针和队尾指针 
	int level[MaxSize];//定义存储结点层数的数组 
	BiTNode* p = T;//定义遍历指针 p,初始时指向根结点 
	int k = 1;//定义变量 k 记录指针 p 指向结点所在的层数 ,初始时有结点,说明有高度,k从1开始,
	Q[rear] = p;//根结点入队 
	level[rear] = k;//记录根结点所在层数为 1 
	rear++;//尾指针后移 
	//遍历二叉树,目的是得到结点所在层数的数组
	while (front < rear) {
    
    //若队列不为空则需继续循环 
		p = Q[front];//出队并让 p 指向出队结点 
		k = level[front];//更新 k 为出队结点所在层数 ,p变了k也要变
		front++;//头指针后移 
		if (p->lchild) {
    
    //若出队结点有左孩子 
			Q[rear] = p->lchild;//将该结点左孩子入队
			level[rear] = k + 1;//新入队结点所在层数为 k+1 
			rear++;//尾指针后移 
		}
		if (p->rchild) {
    
    //若出队结点有右孩子 
			Q[rear] = p->rchild;//将该结点右孩子入队 
			level[rear] = k + 1;//新入队结点所在层数为 k+1 
			rear++;//尾指针后移 
		}
	}
	//查找最大的宽度
	int max = 0, i = 0, n;//定义 max 记录宽度,i 作为遍历索引,n 记录每一层结点数 
	k = 1;//k 用来表示所计数的是第几层,初始时等于 1 表示计数第一层 
	while (i < rear) {
    
    //遍历记录结点层数的数组 
		n = 0;//对每一层结点计数时都需初始化变量 n 
		while (i < rear && level[i] == k) {
    
    //对第 k 层结点进行计数 
			n++;
			i++;
		}
		k++;//本层计数结束,更新变量 k,准备对下一层结点计数 
		if (n > max)//判断此层结点数是否为当前遍历过的最大宽度
			max = n;
	}
	return max;//返回此树的宽度 
}

In the code, first set the array element corresponding to the root node to 1, which means that the root node is on the first layer.

19 Please write an algorithm for preorder non-recursive traversal of a binary tree.
  1. Use the recursive work stack for recursion, and define the stack yourself for non-recursion;
  2. Preorder (root->left->right), define the traversal pointer p, initially point to the root node, print, push the node into the stack (because it needs to jump from the left subtree to the right subtree, it cannot be realized without the stack From the left subtree back to the root and then to the right subtree), process the left subtree, after the left subtree has been processed, it will pop out of the stack to process the right subtree ,
  3. Specifically, it is the same as the code, ifThe p pointer is not empty or the stack is not empty, keep looping, if the stack is empty, the p pointer is not empty (this is the case at the beginning), push the stack, traverse the left subtree, traverse multiple times, and then the p pointer is empty, indicating that the left subtree has been traversed, and it is necessary By popping the stack, find the right subtree for traversal; if the stack is not empty, but the p pointer is empty, it means that the stack has been pushed multiple times to the left and right child nodes of the leaf node, so it is necessary to find the upper layer by popping the stack The right subtree; finally p is NULL and the stack is empty, indicating that the traversal is over.
  4. The cycle conditions of this type of topic pay attention to the beginning, when the leaf node is reached, and when the left and right subtrees are empty.
void PreOrder(BiTree T) {
    
    
	Stack S;//定义一个栈 S 
	InitStack(S);//初始化栈 S 
	BiTNode* p = T;//定义遍历指针 p,初始时指向根结点 
	while (p || !IsEmpty(S)) {
    
    //若 p 指针不为空或栈 S 不为空则继续循环 
		if (p != NULL) {
    
    //若 p 指针不为空 
			printf("%d", p->data);//打印此结点数据域中的数据值 
			Push(S, p);//将此结点压入栈 S 中 
			p = p->lchild;//遍历指针 p 继续遍历此结点的左子树 
		}
		else {
    
    
			Pop(S, p);//若 p 为空则出栈,并让 p 指向出栈结点 
			p = p->rchild;//p 继续遍历此结点的右子树 
		}
	}
}
20 Please write an algorithm for inorder non-recursive traversal of a binary tree.
  1. In-order (left->root->right), after traversing the left subtree and returning to the root, the help of the stack is needed;
  2. Since the left subtree is first, and then the root, the node is pushed into the stack first, and when the left subtree is completely processed, that is, when p is NULL, it needs to be popped out, the element is the root node, and then printed, go to the right Zishu over there.
  3. First, the left subtree is always processed. When the left subtree node is empty, the stack is not empty at this time, indicating that there is no left subtree. Return to the root, print, and process the right node; at the end p is empty and the stack is Empty, end.
  4. When p reaches the left node of the leaf node, p points to NULL. At this time, it needs to be popped, that is, the left -> root in the inorder, and let p point to the popped node. At this time, p points to the root node.
void InOrder(BiTree T) {
    
    
	Stack S;
	InitStack(S);
	BiTNode* p = T;
	while (p || !IsEmpty(S)) {
    
    
		if (p != NULL) {
    
    
			Push(S, p);//将所处理结点压入栈中
			p = p->lchild;//p 继续遍历此结点左子树
		}
		else {
    
    
			Pop(S, p);//若 p 指针为空,则出栈,并让 p 指向出栈结点
			printf("%d", p->data);
			p = p->rchild;//遍历指针 p 继续遍历此结点的右子树
		}
	}
}
21 Please write an algorithm for post-order non-recursive traversal of a binary tree.

⭐⭐⭐⭐⭐

  1. Postorder (left and right roots), the right subtree needs to be processed after the left subtree is processed. At this time, it needs to be implemented through the stack, but there is another problem,From the left subtree to the right subtree, you need to go to the root, and after the right subtree is processed, you also need to go to the root. Both of these may need to go to the root node, which needs to be distinguished(After the left subtree is processed, you need to traverse the root node to access the right subtree; after the right subtree is processed, you need to go to the root and print. The reasons for these two are different, so you need to deal with different situations), so define an r pointer Responsible for recording the last printed node position
  2. The else branch means, when p points to nothing, whether the root node has a right child, and whether the right child of the root node has been processed, depending on the situation.
  3. In addition, the meaning of else: when p points to empty, it needs to be popped, and p points to the popped node, so that p is the root node at this time, and then the operation is performed, but this is the non-recursive idea of ​​pre-order and in-order, for In the follow-up non-recursive algorithm, since both the left and right subtrees reach the root node, it needs to be discussed separately. If only the left subtree needs to jump to the right subtree through the root, we do not need to pop the stack, but need to go to For the right subtree, print the root node after the right subtree is processed; and if the right subtree jumps to the root, it means that it needs to be printed. At this time, the stack is printed. At this timeUpdate record pointer r, indicating that the node was printed in the last traversal. Based on whether the stack is popped from the above, the GetTop() function of the stack is used here to obtain the top element of the stack, which is convenient for judging whether the node has a right child and whether the right child has been traversed.
  4. The preorder and inorder non-recursive algorithms do not need to judge whether p->rchild is NULL, because they are the last step of each cycle. When the next cycle occurs, the loop condition will judge whether p is NULL, and the subsequent non-recursive involves Whether the right subtree has been traversed, so it is necessary to determine whether there is a right subtree.
void PostOrder(BiTree T) {
    
    
	Stack S;
	InitStack(S);
	BiTNode* p = T;
	BiTNode* r = NULL;
	while (p || !IsEmpty(S)) {
    
    
		if (p != NULL) {
    
    
			Push(S, p);//先压栈,然后去到左子树那里
			p = p->lchild;
		}
		else {
    
    
			GetTop(S, p);			
			if ((p->rchild != NULL)&&(p->rchild!=r)) {
    
    //有右孩子且右孩子没有被访问过,左->右
				p = p->rchild;
			}
			else {
    
    //若结点没有右子树或者右子树已被遍历过,右->根
				Pop(S, p);
				printf("%d", p->data);
				r = p;//更新记录指针 
			}
		}
	}
}

​ Simulate it and find that there is a problem. The leaf node in the lower left corner will fall into an infinite loop after processing. The reason is that when p reaches the leaf node in the lower left corner, p!=NULL. At this time, p goes to the left child of the leaf node , at this time p=NULL, enter else, p returns to the leaf node, and if there is no right subtree, it will pop out, print, and then update the record pointer. At this time, p has not changed, making p!=NULL, thus caught in a cycle,The following code will empty the traversal pointer p after each update of the record pointer

void PostOrder(BiTree T) {
    
    
	Stack S;//定义栈 S 
	InitStack(S);//初始化栈 S 
	BiTNode* p = T;//定义遍历指针 p,初始时指向根结点 
	BiTNode* r = NULL;//定义记录指针 r,负责记录上一个打印的结点位置 
	while (p || !IsEmpty(S)) {
    
    //若 p 指针不为空或栈不为空则继续循环 
		if (p != NULL) {
    
    //若 p 指针不为空 
			Push(S, p);//将所处理结点压入栈中 
			p = p->lchild;//p 继续遍历此结点左子树 
		}
		else {
    
    
			GetTop(S, p);//若 p 指针为空则 p 指向栈顶结点 
			if (p->rchild && p->rchild != r)//判断此结点是否有右孩子以及是否遍历 
				p = p->rchild;//若结点有右孩子且未被遍历则 p 继续遍历其右子树 
			else {
    
    //若结点没有右子树或者右子树已被遍历过 
				Pop(S, p);//出栈,并让 p 指向其出栈结点 
				printf("%d", p->data);//打印此结点数据域中的数据 
				r = p;//更新记录指针 
				p = NULL;//将遍历指针置空 
			}
		}
	}
}

对于后续非递归遍历算法,当你遍历打印某个结点时,栈中的结点就是该结点的根,也就是遍历某个结点时候栈中的元素都是其祖先,后续打印某结点的祖先结点,打印根节点到某结点的路径,都是后续非递归遍历算法的改写。

22 To find a node with value x in a binary tree, try to write an algorithm to print all the ancestors of the node with value x, assuming that there is not more than one node with value x.
  1. Post-order non-recursive traversal, the stack contains x and all its ancestor nodes, so writing this type of ancestor node is essentially writing a non-recursive version of post-order traversal , just changing the printing operation into a judgment value of x, If they are equal, pop out the stack and print its ancestor nodes.
void Search_x_father(BiTree T,int x) {
    
    
	Stack S;
	InitStack(S);
	BiTNode* p = T;
	BiTNode* r = NULL;
	while (p || !IsEmpty(S)) {
    
    
		if (p != NULL) {
    
    
			Push(S, p);
			p = p->lchild;
		}
		else {
    
    
			GetTop(S, p);//p 指向栈顶结点但不出栈
			if (p->rchild && p->rchild != r) {
    
    //若该结点有右子树且未被访问
				p = p->rchild;
			}
			else {
    
    //若该结点无右子树或者右子树已经被访问
				Pop(S, p);//出栈并让 p 指向出栈结点
				if (p->data == x) {
    
    //是我们要找的值
					while (!IsEmpty(S)) {
    
    //打印栈中的元素
						Pop(S, p);//出栈并让 p 指向出栈结点
						printf("%d", p->data);
					}
				}
				else {
    
    //不是我们要找的值
					r = p;//更新记录指针位置
					p = NULL;//将指针 p 置空进行下一次循环判断
				}
			}
		}
	}
}
23 p and q are respectively pointers to any two nodes in a binary tree. Try to write an algorithm to find the nearest common node between p and q and return it.
  1. The idea is to find all the ancestor nodes of the two nodes respectively, and then compare them. Here, post-order non-recursive traversal is used (in each traversal process, the elements in the stack are all ancestors of the node);
  2. Specifically, find p or q first (it doesn’t matter whoever finds it first), copy the content in the stack to the newly created stack 1 after finding it, then continue to find p/q that has not been found, and then copy the content after finding it Go to the newly created stack 2, because it involves the copying of the stack, so the array is used here for easy copying (the standard stack needs to be pushed in and out of the stack, which is more complicated, and a for loop is enough for array copying);
  3. Note that here is to find the common node and return, so the function type needs to be paid attention to.
  4. After the post-order non-recursive execution is completed, it is necessary to find the nearest common node (from bottom to top, from the leaf node to the most ancestor node)
  5. Don't forget to update the stack top pointer after copying the stack.
BiTNode* FindAncestor(BiTree T, BiTNode* p, BiTNode* q) {
    
    
	BiTNode* bt = T;
	BiTNode* r = NULL;
	//定义三个栈,因为要复制
	BiTNode* S[MaxSize];
	BiTNode* S1[MaxSize],* S2[MaxSize];
	int top = -1, top1 = -1, top2 = -1;
	int temp;//复制元素时使用
	while (bt || top!=-1) {
    
    //栈不为空
		if (bt != NULL) {
    
    
			S[++top] = bt;//入栈
			bt = bt->lchild;
		}
		else {
    
    //若遍历指针为空
			bt = S[top];//bt 指向栈顶结点但不出栈
			if (bt->rchild && bt->rchild != r) {
    
    //若该结点有右孩子且未被访问
				bt = bt->rchild;//bt 遍历该结点右子树
			}
			else {
    
    //若该结点没有右孩子或者右孩子已经被访问
				bt = S[top];
				top--;//出栈bt指向出栈结点
				if (bt == p) {
    
    //如果该节点是p结点,复制栈S到栈S1
					for (temp = 0; temp <= top; temp++) {
    
    
						S1[temp] = S[temp];
					}
					top1 = top;//更新 S1 栈顶指针
				}
				if (bt == q) {
    
    
					for (temp = 0; temp <= top; temp++) {
    
    
						S2[temp] = S[temp];
					}
					top2 = top;
				}
				//更新r和bt
				r = bt;//更新记录指针
				bt = NULL;//bt 指针置空
			}
		}
	}
	//查找最近公共结点
	for (int i = top1; i >= 0; i--) {
    
    
		for (int j = top2; j >= 0; j--) {
    
    
			if (S1[i] == S2[j]) {
    
    
				return S1[i];//若找到即返回指向最近公共结点的指针变量 
			}
		}
	}
	return NULL;
}
24 Assuming that a binary tree is stored in a binary linked list, please design an algorithm to output the path from the root node to each leaf node.
  1. The output path also uses post-order non-recursive traversal to define the auxiliary stack S, here to judge whether each node is a leaf node;
  2. Since the path from the root node to each leaf node needs to be output here, if the call stack is used in the pseudo-code, each printing path needs to be popped, printed, popped, and printed, which is troublesome. In addition, because it is root -> leaf Nodes are printed from bottom to top in the stack, so you can define a stack of array type for easy traversal and printing (for loop printing from subscript 0 means printing from the bottom line);
  3. The element stored in the stack defined here is a node type with a data field, so the 23rd line of the code is S[i]->data, and the leaf node needs to be printed (because this node is first popped out of the stack and then printed, the stack only its ancestors);
  4. This type of topic first looks at the size of the subsequent non-recursive traversal, so it usually starts at line 19, and the code of the innermost else is rewritten, because it is necessary to prepare for related operations on the node after entering this loop, and before that are all In order to let it enter the corresponding "road".
void AllPath(BiTree T) {
    
    //改写后序非递归遍历
	BiTNode* p = T;
	BiTNode* r = NULL;//定义遍历指针 p,记录指针 r
	BiTNode* S[MaxSize];//定义栈 S
	int top = -1;//定义栈顶指针
	while (p != NULL || top != -1) {
    
    
		if (p != NULL) {
    
    
			S[++top] = p;//让 p 所指结点入栈 
			p = p->lchild;
		}
		else {
    
    
			p = S[top];//p 指向栈顶结点但不出栈 
			if (p->rchild && p->rchild != r) {
    
    //若 p 所指结点有右子树且未被访问 
				p = p->rchild;
			}
			else {
    
    
				p = S[top--];//出栈,并让 p 指向其出栈结点
				if (p->lchild == NULL && p->rchild == NULL) {
    
    
					for (int i = 0; i <= top; i++) {
    
    
						printf("%d", S[i]->data);//打印栈中所有结点数据
					}
					printf("%d", p->data);//打印此叶子结点数据
				}
				r = p;//更新记录指针 r 
				p = NULL;//将 p 指针置空 
			}
		}
	}
}
25 Design an algorithm to connect the leaf nodes of the binary tree in order from left to right into a singly linked list, and the head pointer is head. The binary tree is stored in the form of a binary linked list, and the right pointer field of the leaf node is used to store the single linked list pointer when linking.
  1. Link from left to right, the head pointer head points to the leftmost leaf node;
  2. Traversal is indispensable, pre-order (root left and right) middle order (left root right) post-order (left and right root), regardless of the position of the root, these three discoveries are all traversed from left -> right, soThese three traversal methods can traverse leaf nodes, here by rewriting inorder traversal (left root right);
  3. According to the meaning of the title, first define a table header pointer head, and then because you need to link the leaf nodes, you need to define a pre pointer to point to the leaf node that has been linked recently (record the leaf node traversed last time), if the new To find the leaf node, you can use pre->rchild=the newly found leaf node, and then update the pre pointer;
  4. Judging whether it is the first leaf node can judge whether pre is NULL.
BiTNode* head = NULL, * pre = NULL;//定义头指针 head 和记录指针 pre 
void Link(BiTree& T) {
    
    
	if (T != NULL) {
    
    //改写中序递归遍历算法 
		Link(T->lchild);//递归遍历左子树
		//判断此结点为叶子结点 
		if (T->lchild == NULL && T->rchild == NULL) {
    
    
			if (pre == NULL) {
    
    //判断此结点是否为访问到的第一个叶子结点 
				head = T;//若为第一个叶子结点则让头指针 head 指向它 
				pre = T;//pre 负责记录上一次处理的叶子结点,所以进行更新 
			}
			else {
    
    //若此结点不是第一个叶子结点 
				pre->rchild = T;//直接让上一个访问的叶子结点指向此结点 
				pre = T;//更新 pre 指针位置 
			}
		}
		Link(T->rchild);//递归遍历右子树 
	}
}
26 The expression (a-(b+c))*(d/e) is stored in a binary tree with a binary linked list as the storage structure as shown in the figure below (the data field of the binary tree node is character type), write The program evaluates the expression. (The operands in the expression are all one-bit integers)

Explanation: The function int op(int A, int B, char C) returns the value of the calculation formula with C as the operator and A and B as the operands, for example, if C is '+', it returns A+B value.

The transfer of the external link image failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly.

  1. Expressions include operands and operators,leaf nodeare operands,dual branch nodeIt is an operator . For a double-branch node, the value of its left and right subtrees is calculated recursively. For a leaf node (the data field of the node is a character type, such as '0''1''2', it cannot directly participate in the calculation , the computer saves the ASCII code, to convert the character type into an integer type, you can use the corresponding ASCII code minus the ASCII code of '0'), and then return is the corresponding number of 0-9;
  2. Recursively, divide it into left and right subtrees, calculate them separately, and call the op function;
int Compute(BiTree T) {
    
    
	if (T == NULL) {
    
    
		return 0;
	}
	int A, B;//定义两个变量分别接受左右子树计算的结果
	if (T->lchild != NULL && T->rchild != NULL) {
    
    //若结点为双分支结点 
		A = Compute(T->lchild);//递归计算左子树的值并用 A 接收 
		B = Compute(T->rchild);//递归计算右子树的值并用 B 接收 
		return op(A, B, T->data);//计算左右子树运算结果并返回 
	}
	else {
    
    //若结点为叶子结点 
		return T->data - '0';//将字符型变量转换为数值(ASCII 码)return T->data是错的 
	}
}
27 Try to design an algorithm for judging whether two binary trees are similar. The so-called binary tree T1 is similar to T2 means that both T1 and T2 are empty binary trees or have only one root node; or the left subtree of T1 is similar to the left subtree of T2, and the right subtree of T1 is similar to that of T2 The right subtrees of are similar.
  1. The similarity of this question refers to whether the structure of the binary tree is the same regardless of the data;
  2. Use recursion to judge whether the left and right subtrees are similar;
  3. Recursion boundary: Here are two, both trees are empty, similar, one tree is empty, the other tree is not empty, indicating that they are not similar.
int Similar(BiTree T1, BiTree T2) {
    
    //结点结构一样即为相似 
	定义两个变量分别用于接收左右子树是否相似 
	int left, right;
	if (T1 == NULL && T2 == NULL) {
    
    
		return 1;
	}
	else if (T1 == NULL || T2 == NULL) {
    
    
		return 0;
	}
	else {
    
    //递归式
		left = Similar(T1->lchild, T2->lchild);//递归判断两棵树左子树是否相似 
		right = Similar(T1->rchild, T2->rchild);//递归判断两棵树右子树是否相似 
		//return left && right;//若左右子树都相似则两棵树相似,返回 1 
		if (left == 1 && right == 1) {
    
    
			return 1;//相似
		}
		else {
    
    
			return 0;
		}
	}
}
28 In the binary linked list storage structure of the binary tree, add a parent pointer pointing to the parent node, design an algorithm, assign a value to this pointer, and output the paths from all nodes to the root node.
  1. Modify the structure of the original tree node, increase the parent pointer, then assign a value, and finally output the path from all nodes to the root node.
  2. When assigning values, use preorder traversal (root left and right) , process the root first, and then the left and right nodes, so it is better to define a q pointer from the child node to the father node, and let the parent pointer of the node point to q, the assignment is realized; but in the code, it should be noted that the root node has no parent node, it needs to be empty, and it should be empty at the beginning, so when calling the Func() function, the parameter passed in should be NULL;
  3. To output the path from all nodes to the root node, you can first write a function of the path from the node to the root node, and then call the function for all nodes (traversal).
  4. The parent of the root node is empty, which is the condition for judging the end of the loop;
  5. When traversing the tree, any traversal method can be used, because it only needs to be traversed.
typedef struct BiTNode {
    
    
	int data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
	struct BiTNode* parent;
}BiTNode,*BiTree;
//对parent指针赋值
void Func(BiTree& T, BiTNode* q) {
    
    //指针 q 用来记录T的双亲结点 
	if (T != NULL) {
    
    //改写先序递归遍历 
		T->parent = q;//遍历结点的 parent 指针指向双亲结点 
		q = T;//更新指针 q 的位置 
		Func(T->lchild, q);//递归遍历左子树 
		Func(T->rchild, q);//递归遍历右子树 
	}
}
//打印单个结点到根结点的路径 
void PrintPath(BiTNode* p) {
    
    
	while (p != NULL) {
    
    //只要 p 不为空则继续循环 
		printf("%d", p->data);//打印结点数据域中数据 
		p = p->parent;//p 顺着 parent 指针遍历 
	}
}
//打印所有结点到根结点的路径 
void AllPath(BiTree T) {
    
    
	if (T != NULL) {
    
    //只要 p 不为空则继续循环 
		PrintPath(T);//打印所处理结点到根结点路径 
		AllPath(T->lchild);//递归遍历左子树 
		AllPath(T->rchild);//递归遍历右子树 
	}
}
29 There is a binary tree stored in a one-dimensional array A in the form of sequential storage. The data stored in the nodes in the tree is character type, and the null pointer field is represented by the character '#' in the array. Please design an algorithm to change it into a binary linked list storage method. (Assume that the number of elements in array A is n, starting from subscript 1)
  1. The ordinary binary tree exists in the array, and the binary tree needs to be supplemented into a complete binary tree. The NULL pointer field given in the title is represented by #;
  2. The binary linked list consists of a left pointer field, a data field, and a right pointer field. Since the subscript here starts with 1,There is a relationship between the array subscript and the node. The subscript of the root node is i, the position of the left child node is 2i, and the position of the right child node is 2i+1
  3. Function type BiTree, after each new node is created, returns the position of the newly created node;
  4. Why does it involve i>n? For example, when i is 5, enter the next recursion and go to its left subtree. At this time, i=10>n, so return NULL.

The transfer of the external link image failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly.

BiTree Create(char A[], int i, int n) {
    
    //i 为索引,n 为数组中元素个数 
	
	if(i>n||A[i]=='#'){
    
    
		return NULL;//若 i≥n 则代表后续已无结点则返回 NULL 
    }
    else{
    
    //只有 i<n 才有意义 
		BiTNode* p = (BiTNode*)malloc(sizeof(BiTNode));//申请内存空间 
		p->data = A[i];//给结点数据域赋值 
		p->lchild = Create(A, 2*i, n);//递归处理左子树 
		p->rchild = Create(A, 2*i+1, n);//递归处理右子树 
		return p; //返回结点位置
	}
}
30 Suppose the values ​​of each node in a binary tree are different from each other, and its preorder traversal sequence and inorder traversal sequence are respectively stored in two one-dimensional arrays A[1...n] and B[1...n], try to write The algorithm builds the binary linked list of the binary tree.

Precedence: ABCDE

Insequence: BCAED

The binary tree built is as follows:

A

B D

NULL C E NULL

  1. When writing code, it is similar to manually determining the binary tree structure by ourselves. When we get the pre-order and in-order sequences, we first find the first node of the pre-order recursive traversal, which is the root node of the whole tree. At this time After determining the root node of the whole tree, you can create the node, then find the root node in the in-order traversal sequence, and divide the sequence into left and right parts, that is, the left subtree and the right subtree;

  2. The pre-order traversal sequence (left and right) and the middle-order traversal sequence (left root and right) can determine a unique binary tree, and the first node of the pre-order traversal sequence is the root node of the entire tree;

  3. Nodes need to be divided into left and right parts in the inorder traversal sequence

  4. The low and high in the code refer to who is the leftmost and rightmost in the array. After the root node is determined, the B array also needs to go to the root node to facilitate the subsequent division of the tree into left subtrees and right subtrees, so there is a for loop;

  5. Since the array subscript in the title starts from 1, record the number of left and right subtree nodes llen = i - low2; rlen = high2 - i

  6. When recursively creating the left subtree (left half), for the A array, the root is the root, which needs to be discharged during recursion (already used), and the end position is low1 + llen, which is not low1+1 + llen (you can Try it yourself) For the B array, the beginning is the leftmost, and the end is the one before the root node

    p->lchild = Create(A, low1 + 1, low1 + llen, B, low2, low2 + llen - 1);
    
  7. When recursively creating the right subtree, you can also simulate it yourself

BiTree Create(char A[], int low1, int high1, char B[], int low2, int high2) {
    
    
	BiTNode* p = (BiTNode*)malloc(sizeof(BiTNode));//给根结点分配内存空间
	p->data = A[low1];//为根结点数据域赋值
	int i;//定义变量 i,记录中序序列中根结点的位置
	for (i = low2; B[i] != p->data; i++);//循环使变量 i 指向中序序列中根结点的位置
	int llen = i - low2;//llen 记录左子树结点个数
	int rlen = high2 - i;//rlen 记录右子树结点个数
	if (llen) {
    
    //若左子树有结点则递归创建左子树
		p->lchild = Create(A, low1 + 1, low1 + llen, B, low2, low2 + llen - 1);
	}
	else {
    
    //若左子树已无结点则让其左指针域赋 NULL
		p->lchild = NULL;
	}
	if (rlen) {
    
    //若右子树有结点则递归创建右子树
		p->rchild = Create(A, high1 - rlen + 1, high1, B, high2 - rlen + 1, high2);
	}
	else {
    
    //若右子树已无结点则让其右指针域赋 NULL
		p->rchild = NULL;
	}
	return p;//最后返回所创建树的根结点
}
31 There is a full binary tree (all node values ​​are different), its preorder sequence is known as pre, and an algorithm is designed to find its postorder sequence post.
  1. The first node of the preorder sequence is the root node and the last node of the postorder sequence;
  2. Features of full binary tree : If you do not look at the root node, the number of nodes in the left and right subtrees is the same, you can divide the nodes except the root node into two, and then divide the two pieces, the left one is the left subtree, and the right one is the right subtree, and then recurse.
  3. l1 and h1 are the leftmost and rightmost positions of the preorder sequence (all h1>=l1 are meaningful), l2 and h2 are the leftmost and rightmost positions of the postorder sequence (all h1>=l1 only makes sense when
  4. The operation of assigning a value to the root node of the post array in the code.
void PreToPost(char pre[], int l1, int h1, char post[], int l2, int h2) {
    
    
	int half;//定义 half 变量记录左子树(右子树)结点个数
	if (h1 >= l1) {
    
    //h1≥l1 才有意义(先序遍历)
		post[h2] = pre[l1];//后序序列最后一个即为根结点,也就是先序序列第一个
		half = (h1 - l1) / 2;//因为是满二叉树,所以左右子树结点个数相等
		PreToPost(pre, l1 + 1, l1 + half, post, l2, l2 + half - 1);//递归处理左子树
		PreToPost(pre, l1 + 1 + half, h1, post, l2 + half, h2 - 1);//递归处理右子树
	}
}

/llen records the number of nodes in the left subtree
int rlen = high2 - i;//rlen records the number of nodes in the right subtree
if (llen) {//If the left subtree has nodes, recursively create the left subtree
p- >lchild = Create(A, low1 + 1, low1 + llen, B, low2, low2 + llen - 1); } else {
//
If the left subtree has no nodes, assign NULL to its left pointer field
p-> lchild = NULL;
}
if (rlen) {//If the right subtree has a node, recursively create the right subtree
p->rchild = Create(A, high1 - rlen + 1, high1, B, high2 - rlen + 1, high2);
}
else {//If the right subtree has no nodes, assign NULL to its right pointer field
p->rchild = NULL;
}
return p;//Finally return the root node of the created tree
}




##### 31 设有一棵满二叉树(所有结点值均不同),已知其先序序列为 pre,设计一个算法求其后序序列 post。

1. 先序序列的第一个结点,就是根节点,也是后序序列的最后一个结点;
2. ==**满二叉树特点**:如果不看根节点,其左右子树的结点数量是一样的==,可以将除根节点以外的结点一分为二,然后分出来的两块,左边的就是左子树,右边的就是右子树,然后递归。
3. l1和h1是先序序列最左边的位置和最右边的位置(所有h1>=l1时才有意义),l2和h2是后序序列最左边的位置和最右边的位置(所有h1>=l1时才有意义)
4. 代码中给post数组赋值的根节点的操作。

~~~cpp
void PreToPost(char pre[], int l1, int h1, char post[], int l2, int h2) {
	int half;//定义 half 变量记录左子树(右子树)结点个数
	if (h1 >= l1) {//h1≥l1 才有意义(先序遍历)
		post[h2] = pre[l1];//后序序列最后一个即为根结点,也就是先序序列第一个
		half = (h1 - l1) / 2;//因为是满二叉树,所以左右子树结点个数相等
		PreToPost(pre, l1 + 1, l1 + half, post, l2, l2 + half - 1);//递归处理左子树
		PreToPost(pre, l1 + 1 + half, h1, post, l2 + half, h2 - 1);//递归处理右子树
	}
}

Guess you like

Origin blog.csdn.net/knighthood2001/article/details/132721614