Flatten Binary Tree的几种思路

本文探讨了将二叉树转换为链表的不同方法,包括递归与非递归实现,并详细介绍了前序遍历的具体操作流程。

简介

  在之前的一些学习中有几个地方碰到将二叉树转化成链表的问题。它们虽然各不相同,但是如果仔细分析它们的具体过程,我们会发现其中有一些规律可以遵循的。

 

问题讨论

  这个问题比较有意思的地方在于有这么一个特性。我们定义的二叉树一般有几种常用的遍历方式。比如前序,中序,后序以及层次遍历。它们的每种遍历方式所经历过的节点就构成了一个序列。如果我们需要将一棵二叉树转换成对应的链表,它们所要构成的链表的顺序基本上就和我们遍历的顺序一致。

 

通用思路

  对于上述的问题,如果我们针对它们各种不同的情况来进行遍历的话,我们首先能想到的第一个想法就是递归遍历的办法。当然,光一个递归遍历还是不够的。因为我们需要将它们串起来,也就是说要修改它们的指针来使得它们构成一个对应的双向链表。如果没有其他限制的情况下,我们可以考虑用一个队列来将每次遍历访问的元素保存起来。然后再按照队列的顺序将它们一个个的拼接起来。

  假设我们定义的树节点元素如下:

 public class TreeNode {
 	int val;
 	TreeNode left;
 	TreeNode right;
 	TreeNode(int x) { val = x; }
 }

 

前序

  前序遍历的递归方法只需要稍微做一点修改就可以达到我们期望的结果:

 

public void flattenTree(TreeNode root) {
	if(root == null) return;
	Queue<TreeNode> queue = new LinkedList<>();
	flatten(root, queue);
	Node node = queue.remove();
	node.left = null;
	while(!queue.isEmpty()) {
		Node temp = queue.remove();
		node.right = temp;
		temp.left = node;
		node = temp;
	}
	node.right = null;
}

public void flatten(TreeNode node, Queue<TreeNode> queue) {
	if(node == null) return;
	queue.add(node);
	flatten(node.left, queue);
	flatten(node.right, queue);
}

  这种具体的实现方法利用了原有树的递归调用。不过在调用的过程中将真正需要访问处理的元素加入到一个队列中,这样通过这个队列作为传递的参数,它将最终保存我们期望的结果。然后剩下的步骤就是将这些处理的元素一个个出队列并拼接形成一个链表。

  上面的方法是用递归的方式实现了这么个转换的过程。如果我们想用非递归的方式来处理也好办。这里要利用到一个栈。我们也只是需要在栈处理元素的某个时候来将元素加入队列。一个对应的参考实现如下:

 

public void flattenTree(TreeNode root) {
	if(root == null) return;
	Queue<TreeNode> queue = new LinkedList<>();
	Stack<TreeNode> stack = new Stack<>();
	TreeNode node = root;
	while(node != null || !stack.isEmpty()) {
		if(node != null) {
			queue.add(node);
			if(node.right != null) stack.push(node.right);
			node = node.left;
		} else if(!stack.isEmpty()) {
			node = stack.pop();
		}
	}
	// process the queue, same as before
	node = queue.remove();
	node.left = null;
	while(!queue.isEmpty()) {
		Node temp = queue.remove();
		node.right = temp;
		temp.left = node;
		node = temp;
	}
	node.right = null;	
}

  没什么巧的,这里不过是在非递归的前序遍历实现里加了个壳。对应后面的中序、后序以及层次遍历实现其实都可以用类似的套路来对付。这里可以参考后面的文章来处理。

 

总结

  将二叉树转换成对应的链表的方式有若干种。主要取决于我们要转换成的链表和我们遍历树的关系。对于我们有对应关系的构造,我们可以用常用的递归和非递归方法去首先遍历这课树。在遍历的过程中将访问到的节点放到队列中。后面再统一处理。

  当然,针对一些具体问题的变化中,它还有一些具体的实现差别。比如说在有些要求直接变换不能使用额外存储的情况下。我们需要去发现它们每个节点的前一个位置和后一个位置的关系然后迭代的处理。在某些要求将元素节点转换成循环链表的情况下,我们可以考虑一些递归的解法。这些都是一些问题变体的应用。

 

参考材料

http://shmilyaw-hotmail-com.iteye.com/blog/1828011

http://shmilyaw-hotmail-com.iteye.com/blog/2289879

http://cslibrary.stanford.edu/109/TreeListRecursion.html

集成学习中Bagging近几年有一些新的热门方法,以下进行详细介绍: ### 极端随机树(Extra-Trees) 极端随机树是对随机森林的一种扩展和改进。在构建决策树时,随机森林会在一个特征的所有可能划分点中寻找最优划分点;而极端随机树则是随机选择划分点,进一步增强了模型的随机性。这种方法不仅能够减少模型的方差,还能在一定程度上降低计算成本,提高训练速度。 ```python from sklearn.ensemble import ExtraTreesClassifier from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 加载数据集 iris = load_iris() X = iris.data y = iris.target # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 创建极端随机树分类器 extra_trees = ExtraTreesClassifier(n_estimators=100, random_state=42) extra_trees.fit(X_train, y_train) # 预测 y_pred = extra_trees.predict(X_test) # 计算准确率 accuracy = accuracy_score(y_test, y_pred) print(f"极端随机树准确率: {accuracy}") ``` ### 自助聚合神经网络(Bagging Neural Networks) 将Bagging思想应用于神经网络领域,通过对神经网络进行多次训练,每次使用不同的自助采样数据集,最后将多个神经网络的预测结果进行聚合。这种方法可以有效减少神经网络的过拟合问题,提高模型的泛化能力。 ```python import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split import numpy as np # 生成数据集 X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=0, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 定义Bagging神经网络模型数量 num_models = 5 models = [] for _ in range(num_models): # 自助采样 indices = np.random.choice(len(X_train), size=len(X_train), replace=True) X_sample = X_train[indices] y_sample = y_train[indices] # 构建神经网络模型 model = Sequential([ Dense(10, activation='relu', input_shape=(10,)), Dense(1, activation='sigmoid') ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) model.fit(X_sample, y_sample, epochs=10, verbose=0) models.append(model) # 预测 predictions = [] for model in models: y_pred = model.predict(X_test) predictions.append(y_pred.flatten()) # 聚合预测结果 ensemble_pred = np.round(np.mean(predictions, axis=0)) # 计算准确率 accuracy = np.mean(ensemble_pred == y_test) print(f"自助聚合神经网络准确率: {accuracy}") ``` ### 自适应Bagging(Adaptive Bagging) 自适应Bagging在传统Bagging的基础上,根据每个基学习器的性能动态调整其在最终决策中的权重。表现较好的基学习器会被赋予更高的权重,从而提高整体模型的性能。 ```python from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 加载数据集 iris = load_iris() X = iris.data y = iris.target # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 创建自适应Bagging分类器 bagging = BaggingClassifier(base_estimator=DecisionTreeClassifier(), n_estimators=100, random_state=42) bagging.fit(X_train, y_train) # 预测 y_pred = bagging.predict(X_test) # 计算准确率 accuracy = accuracy_score(y_test, y_pred) print(f"自适应Bagging准确率: {accuracy}") ``` ### 多核Bagging(Multi-kernel Bagging) 多核Bagging结合了多核学习和Bagging的思想,在多个不同的核函数上训练基学习器,然后将这些基学习器的结果进行聚合。这种方法能够充分利用不同核函数的优势,提高模型的表达能力和泛化性能。 ```python from sklearn.multiclass import OneVsRestClassifier from sklearn.svm import SVC from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score import numpy as np # 加载数据集 iris = load_iris() X = iris.data y = iris.target # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 定义不同的核函数 kernels = ['linear', 'rbf', 'poly'] models = [] for kernel in kernels: model = OneVsRestClassifier(SVC(kernel=kernel)) model.fit(X_train, y_train) models.append(model) # 预测 predictions = [] for model in models: y_pred = model.predict(X_test) predictions.append(y_pred) # 聚合预测结果 ensemble_pred = np.apply_along_axis(lambda x: np.bincount(x).argmax(), axis=0, arr=predictions) # 计算准确率 accuracy = accuracy_score(y_test, ensemble_pred) print(f"多核Bagging准确率: {accuracy}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值