王道p150 12.在二叉树中查找值为 x 的结点,试编写算法(用 C语言)打印值为x的结点的所有祖先,假设值为X的结点不多于一个。(c语言代码实现,注释详解)

采用非递归后序遍历,最后访问根结点,访问到值为 x 的结点时,栈中所有元素均为该结点的祖先,依次出栈打印.

本题代码如下(注释详解)

// 寻找指定字符的所有祖先结点  
void ancestor(tree* t, char x)
{
	stack s[10]; // 定义一个大小为10的栈,用于存储二叉树的结点指针和标记位  
	int top = -1; // 初始化栈顶为-1,表示栈为空  
	while (*t != NULL || top != -1) // 当当前节点非空或者栈非空时,继续循环  
	{
		while (*t != NULL) // 当当前结点非空时,将其入栈并向左子树遍历  
		{
			top++;
			s[top].t = *t; // 将当前结点入栈  
			s[top].tag = 0; // 标记位设为0,表示该结点尚未被访问过  
			*t = (*t)->lchild; // 向左子树遍历  
		}
		while (top != -1 && s[top].tag == 1) // 当栈非空且栈顶元素的标记位为1时,出栈(即回退)  
		{
			top--;
		}
		if (top != -1) // 当栈非空时,进行以下操作  
		{
			if (s[top].t->data == x) // 如果栈顶元素的data字段等于指定字符x,则输出所有祖先结点  
			{
				printf("所有的祖先结点为:\n");
				for (int i = 0; i < top; i++) // 遍历栈中所有元素(不包括栈顶元素)并输出其data字段  
				{
					printf("%c ", s[i].t->data);
				}
				break; // 找到指定字符的所有祖先结点后,跳出循环  
			}
			s[top].tag = 1; // 如果栈顶元素的data字段不等于指定字符x,将其标记位设为1,表示该结点已经被访问过  
			*t = s[top].t->rchild; // 向右子树遍历  
		}
	}
}

完整测试代码

#include   
#include 
// 定义一个二叉树结点 
typedef struct treenode
{
	char data; //结点存储的数据  
	struct treenode* lchild, * rchild; // 结点的左右孩子  
} treenode, * tree;
// 定义一个栈结构  
typedef struct
{
	treenode* t; // 栈中存储的是二叉树的结点指针  
	int tag; // 标记位,主要用于记录结点是否已经被访问过  
} stack;
// 建立二叉树  
void buildtree(tree* t)
{
	char ch;
	ch = getchar(); // 从标准输入获取一个字符  
	if (ch == '#') // 如果输入的是'#',则该节点为空  
		*t = NULL;
	else
	{
		*t = (treenode*)malloc(sizeof(treenode)); // 为新的结点分配内存空间  
		(*t)->data = ch; // 将输入的字符赋值给节点的data字段  
		(*t)->lchild = NULL; // 初始化结点的左右孩子为空  
		(*t)->rchild = NULL;
		buildtree(&(*t)->lchild); // 递归建立左子树  
		buildtree(&(*t)->rchild); // 递归建立右子树  
	}
}
// 寻找指定字符的所有祖先结点  
void ancestor(tree* t, char x)
{
	stack s[10]; // 定义一个大小为10的栈,用于存储二叉树的结点指针和标记位  
	int top = -1; // 初始化栈顶为-1,表示栈为空  
	while (*t != NULL || top != -1) // 当当前节点非空或者栈非空时,继续循环  
	{
		while (*t != NULL) // 当当前结点非空时,将其入栈并向左子树遍历  
		{
			top++;
			s[top].t = *t; // 将当前结点入栈  
			s[top].tag = 0; // 标记位设为0,表示该结点尚未被访问过  
			*t = (*t)->lchild; // 向左子树遍历  
		}
		while (top != -1 && s[top].tag == 1) // 当栈非空且栈顶元素的标记位为1时,出栈(即回退)  
		{
			top--;
		}
		if (top != -1) // 当栈非空时,进行以下操作  
		{
			if (s[top].t->data == x) // 如果栈顶元素的data字段等于指定字符x,则输出所有祖先结点  
			{
				printf("所有的祖先结点为:\n");
				for (int i = 0; i < top; i++) // 遍历栈中所有元素(不包括栈顶元素)并输出其data字段  
				{
					printf("%c ", s[i].t->data);
				}
				break; // 找到指定字符的所有祖先结点后,跳出循环  
			}
			s[top].tag = 1; // 如果栈顶元素的data字段不等于指定字符x,将其标记位设为1,表示该结点已经被访问过  
			*t = s[top].t->rchild; // 向右子树遍历  
		}
	}
}
int main()
{
	tree t; // 定义一个二叉树节点指针t  
	buildtree(&t); // 建立二叉树  
	ancestor(&t, 'D'); // 找出字符'D'的所有祖先结点并输出  
	return 0; 
}

用ABD##E##CF##G##测试

/*                       A

            B                        C

D                   E      F                 G     */

你可能感兴趣的:(树,数据结构,c语言,树)