共同祖先(二叉树)(C语言)(icoding

题目

假设二叉树采用二叉链表方式存储, root指向根结点,p所指结点和q所指结点为二叉树中的两个结点,编写一个计算它们的最近的共同祖先,函数定义如下:

BiTNode * nearest_ancestor(BiTree root, BiTNode *p, BiTNode *q);

其中 root 指向二叉树的根结点,p 和 q 分别指向二叉树中的两个结点。
提示:在完成本题时,可利用 path 函数获取p和q两个结点到根结点之间的路径,之后再计算两条公共路径得出最近的共同祖先。path函数及栈相关定义如下:

bool path(BiTNode* root, BiTNode* node, Stack* s);

#define Stack_Size 50
typedef BiTNode* ElemType;
typedef struct{
    ElemType elem[Stack_Size];
    int top;
}Stack;

void init_stack(Stack *S); // 初始化栈
bool push(Stack* S, ElemType x); //x 入栈
bool pop(Stack* S, ElemType *px); //出栈,元素保存到px所指的单元,函数返回true,栈为空时返回 false
bool top(Stack* S, ElemType *px); //获取栈顶元素,将其保存到px所指的单元,函数返回true,栈满时返回 false
bool is_empty(Stack* S);  // 栈为空时返回 true,否则返回 false

答案

BiTNode* nearest_ancestor(BiTree root, BiTNode* p, BiTNode* q)
{
    int num1 = 0, num2 = 0;
    BiTNode *node1[100], *node2[100];
    Stack s1, s2;
    init_stack(&s1);
    init_stack(&s2);

    path(root, p, &s1);
    path(root, q, &s2);

    while (!is_empty(&s1))
        pop(&s1, &node1[num1++]);
    while (!is_empty(&s2))
        pop(&s2, &node2[num2++]);

    if (num1 < num2)
        for (int i = 0; i < num1; i++) {
            if (node1[i] == node2[num2 - (num1 - i)])
                return node1[i];
        }
    else
        for (int i = 0; i < num2; i++) {
            if (node2[i] == node1[num1 - (num2 - i)])
                return node2[i];
        }
}

收获

思路

  • 利用path函数获得p、q分别到根结点的路径,并且将p与根节点(包括p与根节点在内)之间的所有结点pop到一个初始化后的栈中、将q与根节点(包括q与根节点在内的)之间的所有结点pop到另一个初始化好的栈中。

  • 将两个栈中的元素分别给初始化好的两个指针数组

  • 将num1>num2与num1<=num2两种情况分别考虑(防止num1-(num2+i)为负数)。因为栈的“后进先出”的特性,数组里下标小的元素更靠近栈顶,与p和q相差的结点数目越少,所以i从0开始计数。

 for (int i = 0; i < num1; ++i) { 
        for (int j = 0; j < num2; ++j) {
            if (Node1[i] == Node2[j]) {
                return Node1[i]; 

这样写也可以,但是时间复杂度为n^2,比原代码中时间复杂度为n的代码执行效率低。(都能过)

  • 用于调试该函数的完整代码
#include 
#include 
#include
#define Stack_Size 50

typedef int DataType;

typedef struct Node {
	DataType data;
	struct Node* left=NULL;
	struct Node* right=NULL;
}BiTNode,*BiTree; 

typedef BiTNode* ElemType;
typedef struct {
	ElemType elem[Stack_Size];
	int top;
}Stack;
void init_stack(Stack* S) {
	S->top = -1;
}
bool push(Stack* S, ElemType x) {
	if (S->top == Stack_Size - 1)
		return false;
	S->top++;
	S->elem[S->top] = x;
	return true;
}
bool pop(Stack* S, ElemType* px) {
	if (S->top == -1)
		return false;
	*px = S->elem[S->top];
	S->top--;
	return true;
}
bool top(Stack* S, ElemType* px) {
	if (S->top == -1)
		return false;
	*px = S->elem[S->top];
	return true;
}
bool is_empty(Stack* S) {
	return(S->top == -1 ? true : false);
}//作为一个判断条件
bool path(BiTNode* root, BiTNode* node, Stack* s) {
	BiTree T = root, p;
	if (T == NULL || node == NULL || !is_empty(s))
		return false;
	while (T||!is_empty(s)) {
		while (T) {
			push(s, T);
			if (T == node)
				return true;
			T = T->left;
		}
		top(s,&T);
		if (!T->right || T->right == p) {
			p = T;
			pop(s, &T);
			T = NULL;
		}
		else T = T->right;
	}
	return false;
}
void init_tree(BiTree* node) {
	*node = (BiTree)    malloc(sizeof(BiTNode));

	DataType value;
	DataType  left, right;
	scanf("%d %d %d",&value,&left,&right);
	(*node)->data = value;

	if (left) init_tree(&(*node)->left);
	else (*node)->left = NULL;
	if (right) init_tree(&(*node)->right);
	else (*node)->right = NULL;
}
BiTNode* nearest_ancestor(BiTree root, BiTNode* p, BiTNode* q) {
	int num1 = 0, num2 = 0;
	BiTNode* node1[100],*node2[100];
	Stack s1, s2;
	init_stack(&s1);
	init_stack(&s2);

	path(root, p, &s1);
	path(root, q, &s2);

	while (!is_empty(&s1))
		pop(&s1, &node1[num1++]);
	while (!is_empty(&s2))
		pop(&s2,&node2[num2++]);

	if(num1<num2)
	for (int i = 0;i < num1;i++) {
		if (node1[i] == node2[num2 - (num1- i)])
		return node1[i];
	}
	else
		for (int i = 0;i < num2;i++) {
			if(node2[i]==node1[num1-(num2-i)])
				return node2[i];
		}

}

BiTNode* Node(BiTree root, int dat) {
	if (root == NULL) return NULL;
	if (root->data == dat) return root;

	BiTree res;
	if (res = Node(root->left, dat)) return res;
	if (res = Node(root->right, dat)) return res;
	return NULL;
}

int main(void) {
	freopen("in.txt","r",stdin);
	BiTree a;
	init_tree(&a);

	BiTNode* p, * q;
	int data1, data2;
	scanf("%d %d", &data1, &data2);
	p = Node(a, data1);
	q = Node(a, data2);

	BiTNode* anc = nearest_ancestor(a, p, q);
	printf("%d\n", anc->data);

	return 0;
}


  1. 用栈和堆初始化变量的区别
 typedef struct Node {//用栈初始化变量
	DataType data;
	struct Node* left=NULL;
	struct Node* right=NULL;
}BiTNode,*BiTree; 
void init_tree(BiTree* node) {//用堆初始化变量
	*node = (BiTree)    malloc(sizeof(BiTNode));

	DataType value;
	DataType  left, right;
	scanf("%d %d %d",&value,&left,&right);
	(*node)->data = value;

	if (left) init_tree(&(*node)->left);
	else (*node)->left = NULL;
	if (right) init_tree(&(*node)->right);
	else (*node)->right = NULL;
}

用堆初始化变量:初始化的变量所分配的内存时跟变量size相同的内存空间。
用栈和用堆初始化变量的标志:
用栈初始化变量没有调用malloc()函数,而用堆初始化调用了malloc()函数。
2. 编写一个通过值查找节点的函数
3.调试顺序

你可能感兴趣的:(共同祖先(二叉树)(C语言)(icoding)