`

二叉树前序中序,后序中序,公共最近祖先的实现

 
阅读更多

 

二叉树前序中序,后序中序,公共最近祖先的实现

注释中详细介绍了算法,故不再赘述。

无论是前序还是后序,一个节点的左子树和右子树都是可以看做是分开的,有一定规律可循,故可用递归进行实现。

 

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

const int len = 12;

char pre[len] = "ABDEHCFIJGK";
char mid[len] = "DBHEAIFJCKG";

typedef struct _Node{
	char data;
	struct _Node *left;
	struct _Node *right;
}TreeNode, *Tree;

//  确定c在中序序列mid中的下标,假设树的各个节点的值各不相同
int position(char c) {
	return strchr(mid, c) - mid; 
}

/*  利用前序中序序列创建树
 *    i: 子树的前序序列字符串的首字符在pre[]中的下标
 *    j: 子树的中序序列字符串的首字符在mid[]中的下标
 *  len: 子树的字符串序列的长度
*/
void premidCreateTree(Tree &node, int i, int j, int len) {
	if(len <= 0) {
		node = NULL;
		return;
	}

	node = new TreeNode;
	node->data = pre[i];
	int m = position(pre[i]);
	// i+1 :该node节点的左子树前序序列字符串的首字符在pre[]中的下标
	// j   :该node节点的左子树中序序列字符串的首字符在mid[]中的下标
	// m-j :该node节点的左子树字符串序列的长度
	premidCreateTree(node->left, i+1, j, m-j);
	// i+(m-j)+1  :该node节点的右子树前序序列字符串的首字符在pre[]中的下标
	//       m+1  :该node节点的右子树中序序列字符串的首字符在mid[]中的下标
	// len-1-(m-j):该node节点的右子树字符串序列的长度
	premidCreateTree(node->right, i+(m-j)+1, m+1, len-1-(m-j));
}

//  前序遍历树
void PreTravelTree(Tree &node) {
	if(node) {
		cout << node->data;
		PreTravelTree(node->left);
		PreTravelTree(node->right);
	}
}

/*  利用后序中序序列创建树
  *        i: 子树的后序序列字符串的字符在post[]中的下标
  *        j: 子树的中序序列字符串的首字符在mid[]中的下标
  *      len: 子树的字符串序列的长度
  */
void PostMidCreateTree(PNode &pn, int i, int j, int len) {
	if(len <= 0) {
		node = NULL;
		return;
	}
  pn = new Node;
  pn->v = post[i];
  int m = Position(post[i]);
  PostMidCreateTree(pn->left, i-1-(len-1-(m-j)), j, m-j);//注意参数:m-j左子树的长度,len-1-(m-j)右子树的长度
  PostMidCreateTree(pn->right, i-1, m+1, len-1-(m-j));
}

//  寻找两个节点的最近公共祖先,但是遇到下面这种情况时,会有bug
//            A          寻找B,C的公共祖先,不能用此算法
//           / \
//          B   D
//         /
//        C
int findPNode(Tree root, char a, char b, TreeNode** PNode){
	if(root == NULL) return 0;
	if(root->data == a || root->data == b) {
		return 1;
	}
	int left = findPNode(root->left, a, b, PNode);
	if(left == 2) return 2;
	int right = findPNode(root->right, a, b, PNode);
	if(right == 2) return 2;
	if(left + right == 2) *PNode = root;
	return left + right;
}

// 二叉树是普通的二叉树,节点只有left/right,没有parent指针。
//
//                                           10
//                                         /    \     
//                                        6      14   
//                                       / \    /  \  
//                                      4   8  12   18
//                                     / \
//                                    3   5
//
// 基本思想:记录从根找到node1和node2的路径,然后再把它们的路径用类似的情况一来做分析,比如还是node1=3,node2=8这个case.
// 我们肯定可以从根节点开始找到3这个节点,同时记录下路径3,4,6,10,类似的我们也可以找到8,6,10。
// 我们把这样的信息存储到两个vector里面,把长的vector开始的多余节点3扔掉,从相同剩余长度开始比较,4!=8, 6==6,我们找到了我们的答案。

bool findParentByVector(TreeNode* root, char NData, vector<TreeNode*>& path) {
	if(root == NULL) return false;
	if(root->data != NData) {
		if(findParentByVector(root->left, NData, path)) {
			path.push_back(root);
			return true;
		} else {
			if(findParentByVector(root->right, NData, path)) {
				path.push_back(root);
				return true;
			} else {
				return false;
			}
		}
	} else {
		path.push_back(root);
		return true;
	}
}

TreeNode* findBstNode(TreeNode* root, char a, char b) {
	vector<TreeNode*> path1;
	vector<TreeNode*> path2;
	bool find = false;
	find |= findParentByVector(root, a, path1);
	find &= findParentByVector(root, b, path2);
	if(find) {
		int minSize = path1.size() > path2.size() ? path2.size() : path1.size();
		int th1 = path1.size() - minSize;
		int th2 = path2.size() - minSize;
		for(; th1 < (int)path1.size() && th2 < (int)path2.size(); th1++, th2++) {
			if(path1[th1] == path2[th2]) {
				return path1[th1];
			}
		}	
	}
	return NULL;
}

int main() {
	Tree root = NULL;
	premidCreateTree(root, 0, 0, strlen(mid));
	PreTravelTree(root);

	TreeNode *PNode = NULL;
	/*findPNode(root, 'D', 'B', &PNode);
	cout << endl << PNode->data << endl;*/

	PNode = findBstNode(root, 'I', 'G');
	cout << endl << PNode->data << endl;
	
	getchar();
	return 0;
}

 

 

 

 

 

 

分享到:
评论

相关推荐

    二叉树的基本操作,包括前序、中序、后序遍历的递归和非递归算法

    本文将深入探讨二叉树的前序、中序、后序遍历的递归和非递归算法。 1. **前序遍历**: - **递归算法**:首先访问根节点,然后递归地对左子树进行前序遍历,最后对右子树进行前序遍历。伪代码如下: ``` function...

    二叉树非递归遍历(前序、中序、后序)

    本主题将详细介绍如何非递归地进行二叉树的前序、中序和后序遍历,以及如何使用C语言实现通用栈结构来辅助遍历。 首先,我们来看递归遍历的方法。递归遍历是基于函数调用自身来完成的,对于二叉树,有以下三种遍历...

    二叉树的建立及遍历

    根据前序和中序遍历序列,我们可以唯一地恢复一棵二叉树。下面我们将详细探讨这个过程。 首先,前序遍历的顺序是根节点 -&gt; 左子树 -&gt; 右子树,而中序遍历的顺序是左子树 -&gt; 根节点 -&gt; 右子树。这两个序列结合可以...

    二叉树先中后序线索化及其遍历

    构造线索时,需要在二叉树的每个节点上添加两个额外的线索指针,分别指向其在前序和中序遍历中的后继节点。对于后序遍历,还需要处理更复杂的线索关系。遍历时,根据当前节点的线索指针来决定下一个要访问的节点。 ...

    关于软考-二叉树遍历问题总结前序遍历、后序遍历、中序遍历、递归遍历

    层次遍历常用于社交网络分析,查找最近公共祖先等问题。 在软考中,理解这些遍历方式的概念和实现方法至关重要。对于递归遍历,关键是理解每种遍历方式中节点访问的顺序;对于非递归遍历,需要掌握栈或队列的数据...

    树的创建和遍历(前序、中序、后序),并输出某个节点以前的所有祖先(精美的MFC画面实现)

    本项目聚焦于使用C++语言和MFC(Microsoft Foundation Classes)库实现树的创建、遍历以及输出某个节点的所有祖先。下面将详细阐述相关知识点。 首先,树的基本概念:树是由节点(Vertex)和边(Edge)构成的数据...

    二叉树实现(C++版本)

    实现了二叉树的前序递归创建,非递归层次创建,非递归前序加中序创建;前序、中序、后序的递归遍历以及前、中、后、层次的非递归遍历;操作方面,使用后序递归遍历实现了size()和height()方法;除此,还有find...

    java+kotlin+python+C程序设计习题集分享给需要的同学

    214. 二叉搜索树的最近公共祖先 215. 二叉搜索树的范围和 216. 使二叉树所有路径值相等的最小代价 217. 受限条件下可到达节点的数目 218. 用队列实现栈 219. 找出字符串的可整除数组 220. 找出美丽数组的最小和 221....

    程序开发设计习题文档集合

    214. 二叉搜索树的最近公共祖先 215. 二叉搜索树的范围和 216. 使二叉树所有路径值相等的最小代价 217. 受限条件下可到达节点的数目 218. 用队列实现栈 219. 找出字符串的可整除数组 220. 找出美丽数组的最小和 221....

    二叉树遍历问题先序遍历、中序遍历和后序遍历等等最新详情介绍.docx

    以下提供了一段Java代码示例,展示了二叉树的前序、中序和后序遍历的递归和迭代版本的实现: ```java class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int val) { this.val = val; } } ...

    二叉树基本操作(建树、前中后序遍历非递归实现)

    本压缩包文件“BinTreeBasic”包含了关于二叉树基本操作的实现,特别是非递归方式的前序、中序和后序遍历。 首先,我们来详细解释二叉树的三种遍历方式: 1. **前序遍历**:也称为先根遍历,其顺序为根节点 -&gt; 左...

    二叉树交换左右子树 查询祖先结点

    通常,通过前序遍历、中序遍历或后序遍历的组合,我们可以有效地定位到祖先节点。 前序遍历(根-左-右)是先访问根节点,然后遍历左子树,最后遍历右子树;中序遍历(左-根-右)则是先遍历左子树,再访问根节点,...

    线索二叉树用c#实现

    线索二叉树是一种特殊的二叉树数据结构,它在二叉链表的基础上增加了线索,用于在非递归情况下实现前序、中序和后序遍历。这种数据结构在计算机科学中尤其在算法和数据结构的学习中具有重要意义,因为它允许我们高效...

    python入门-leetcode面试题解之第236题二叉树的最近公共祖先.zip

    本资料包提供的"python入门_leetcode面试题解之第236题二叉树的最近公共祖先"应该包含了详细的Python代码实现,以及对解题思路的阐述,有助于读者深入理解二叉树的性质和操作,以及如何用Python优雅地解决问题。...

    二叉树的相关操作

    首先,非递归建立二叉树通常指的是通过给定的序列(如前序、中序或后序遍历的结果)来构建二叉树。在非递归方法中,我们可以使用栈来辅助构建过程。例如,如果已知前序遍历和中序遍历,我们可以先找到前序遍历中的根...

    树和二叉树习题(老师给的题)含答案

    11. 某二叉树的前序遍历结点访问顺序是 abdgcefh,中序遍历的结点访问顺序是dgbaechf,则其后序遍历的结点访问顺序是 gdbehfca。 答案:C. gdbehfca 12. 在一非空二叉树的中序遍历序列中,根结点的右边只有右子树...

    数据结构 树 练习题

    3. 如果 T2 是由有序树 T 转换而来的二叉树,那么 T 中结点的前序就是 T2 中结点的 A、前序 B、中序 C、后序 D、层中序。 解释:当我们将有序树转换为二叉树时,结点的前序遍历序列将保持不变。 4. 如图所示二叉树...

    BinaryTree.rar

    1、任意输入前序 + 中序序列或者中序 + 后序序列,生成二叉树 3、利用打印二叉树功能显示二叉树的逐步构造过程,使用自上而下的二叉树显示 4、使用EGE(xege.org) / SFML...

    数据结构入门题目(力扣)

    移除链表元素,反转链表,删除排序链表中的重复元素,有效的括号,用栈实现队列,二叉树的前序遍历,二叉树的中序遍历,二叉树的后序遍历,二叉树的层序遍历,二叉树的最大深度,对称二叉树,翻转二叉树,路径总和,二叉搜索树中...

    数据结构课程设计 二叉树的各种遍历算法及树与二叉树的转换程序及报告

    DFS可以实现前序、中序和后序遍历,而BFS则适用于层次遍历,例如找到最近的公共祖先等。 在报告中,应当详细阐述了设计思路、算法实现过程、时间复杂度和空间复杂度分析,以及可能的优化方案。同时,通过示例展示了...

Global site tag (gtag.js) - Google Analytics