数据结构与算法——二叉树

1 树概述

  • :在层次化的数据元素之间有祖先-后代、上级-下属、整体-部分以及其他类似的关系。
  • 根和子树:树t为非空有限集合,其中一个元素为,其余组成t的子树
  • :树根为1级,其孩子是2级,孩子的孩子为3级,以此类推。
  • 高度(深度):树中级的个数。
  • 元素的度:其孩子的个数。
  • 树的度:其元素的度的最大值。

2 二叉树特性及常用操作

2.1 二叉树特性
与普通树根本区别:
(1)每个元素恰好有两棵子树
(2)每个元素的子树是有序的,左子树和右子树
(3)二叉树可以为空
例:表达式树
数据结构与算法——二叉树
特性:
(1)有n各元素,必有n-1条边
(2)有n个元素,高度最小log2(n+1)log_2(n+1)log2​(n+1),最大n
(3)高度为h,最少h个元素,最多2h12^h-12h−1个元素
(4)完全二叉树某元素编号为i,1in1\le i \le n1≤i≤n,有以下关系成立:

  • i=1i=1i=1,该元素为根,其父节点编号为i/2i/2i/2
  • 2i>n2i>n2i>n,该元素无左孩子,否则左孩子为2i2i2i
  • 2i+1>n2i+1>n2i+1>n,该元素无右孩子,否则右孩子为2i+12i+12i+1
    2.2 二叉树描述
    数组描述
    看做缺少部分元素的完全二叉树,适用于缺少的元素数目较少的情况。
    数据结构与算法——二叉树
    从0开始,最坏的空间需求是2n12^n-12n−1(右斜树)
    链表描述
    用一个结构表示:两个指针域+一个element域
    数据结构与算法——二叉树
    具有n个元素的二叉树仅有n-1个边,所以有n+1个指针没有值,被设置成NULL。
#ifndef binaryTreeNode_
#define binaryTreeNode_

using namespace std;

template <class T>
struct binaryTreeNode
{
	T element;
	binaryTreeNode<T>* leftChild,   // left subtree
		* rightChild;  // right subtree

	binaryTreeNode() { leftChild = rightChild = NULL; }
	binaryTreeNode(const T& theElement) :element(theElement)
	{
		leftChild = rightChild = NULL;
	}
	binaryTreeNode(const T& theElement,
		binaryTreeNode* theLeftChild,
		binaryTreeNode* theRightChild)
		:element(theElement)
	{
		leftChild = theLeftChild;
		rightChild = theRightChild;
	}
};
#endif

2.3 二叉树常用操作
数据结构与算法——二叉树
以上操作可通过对二叉树的遍历实现。
2.4 二叉树遍历
常用的4中遍历方法:

  • 前序遍历
template <class T>
void preOrder(binaryTreeNode<T> *t){
	//前序遍历二叉树*t
	if (t != NULL){
		visit(t);//访问树根
		preOrder(t -> leftChild);//前序遍历左子树
		preOrder(t -> rightChild);//前序遍历右子树
	}
}
  • 中序遍历
template <class T>
void inOrder(binaryTreeNode<T> *t){
	//中序遍历二叉树*t
	if (t != NULL){
		inOrder(t -> leftChild);//中序遍历左子树
		visit(t);//访问树根
		inOrder(t -> rightChild);//中序遍历右子树
	}
}
  • 后序遍历
template <class T>
void postOrder(binaryTreeNode<T> *t){
	//后序遍历二叉树*t
	if (t != NULL){
		postOrder(t -> leftChild);//中序遍历左子树
		postOrder(t -> rightChild);//中序遍历右子树
		visit(t);//访问树根
	}
}

前三种方法相同之处:左子树先于右子树遍历
区别在于:对每个节点访问时间不同
***例:***对下图三个数分别用上述三种遍历方法进行遍历
数据结构与算法——二叉树
结果如下:
数据结构与算法——二叉树
其中,遍历方法visit(t)程序如下:

template <class T>
void visit(binaryTreeNode<T> *x){
	cout << x -> element << ' ';
}
  • 层次遍历
    从顶层到底层,在同一层中,从左到右,依次访问树的元素
    需要队列的支持,故很难编写递归程序。
template <class T>
void levelOrder(binaryTreeNode<T> *t)
{
	arrayQueue<binaryTreeNode<T>*> q;
	while (t != NULL)
	{
		theVisit(t);  // visit t

		// put t's children on queue
		if (t->leftChild != NULL)
			q.push(t->leftChild);
		if (t->rightChild != NULL)
			q.push(t->rightChild);

		// get next node to visit
		try { t = q.front(); }
		catch (queueEmpty) { return; }
		q.pop();
	}
}

3 二叉树实现

3.1 抽象数据类型
数据结构与算法——二叉树
3.2 类linkedBinaryTree
声明如下:

template<class E>
class linkedBinaryTree : public binaryTree<binaryTreeNode<E> >
{
public:
	linkedBinaryTree() { root = NULL; treeSize = 0; }
	~linkedBinaryTree() { erase(); };
	bool empty() const { return treeSize == 0; }
	int size() const { return treeSize; }
	E* rootElement() const;
	void makeTree(const E& element,
		linkedBinaryTree<E>&, linkedBinaryTree<E>&);
	linkedBinaryTree<E>& removeLeftSubtree();
	linkedBinaryTree<E>& removeRightSubtree();
	void preOrder(void(*theVisit)(binaryTreeNode<E>*))
	{
		visit = theVisit; preOrder(root);
	}
	void inOrder(void(*theVisit)(binaryTreeNode<E>*))
	{
		visit = theVisit; inOrder(root);
	}
	void postOrder(void(*theVisit)(binaryTreeNode<E>*))
	{
		visit = theVisit; postOrder(root);
	}
	void levelOrder(void(*)(binaryTreeNode<E>*));
	void preOrderOutput() { preOrder(output); cout << endl; }
	void inOrderOutput() { inOrder(output); cout << endl; }
	void postOrderOutput() { postOrder(output); cout << endl; }
	void levelOrderOutput() { levelOrder(output); cout << endl; }
	void erase()
	{
		postOrder(dispose);
		root = NULL;
		treeSize = 0;
	}
	int height() const { return height(root); }
protected:
	binaryTreeNode<E>* root;                // pointer to root
	int treeSize;                           // number of nodes in tree
	static void (*visit)(binaryTreeNode<E>*);      // visit function
	static int count;         // used to count nodes in a subtree
	static void preOrder(binaryTreeNode<E>* t);
	static void inOrder(binaryTreeNode<E>* t);
	static void postOrder(binaryTreeNode<E>* t);
	static void countNodes(binaryTreeNode<E>* t)
	{
		visit = addToCount;
		count = 0;
		preOrder(t);
	}
	static void dispose(binaryTreeNode<E>* t) { delete t; }
	static void output(binaryTreeNode<E>* t)
	{
		cout << t->element << ' ';
	}
	static void addToCount(binaryTreeNode<E>* t)
	{
		count++;
	}
	static int height(binaryTreeNode<E>* t);
};

方法定义略。

4 应用

设置信号放大器
并查集

上一篇:逛画展(二分+队列)


下一篇:leetcode 79 单词搜索