数组表示
数组下标和二叉树编号一一对应(0 下标空出来)
这样有 n 个元素的二叉树最多需要 数组空间(也就是每一层放一个, 上图右侧)
如果根节点放在数组 0 处, 则需要 数组空间
这样空间利用率较低
链表表示
template<class T>
struct binaryTreeNode {
T element; // 数据
// 左右子节点
binaryTreeNode<T>* leftChild, * rightChild;
// 构造函数
binaryTreeNode() {
leftChild = rightChild = NULL;
}
binaryTreeNode(const T& theElement):element(theElement) {
leftChild = rightChild = NULL;
}
binaryTreeNode(const T& theElement,
binaryTreeNode* leftChild,
binaryTreeNode* rightChild):element(theElement)
{
this->leftChild = leftChild;
this->rightChild = rightChild;
}
};
遍历
三种遍历具体步骤: 点击查看
前序遍历
template<class T>
void preOrder(binaryTreeNode<T>* t) {
if (t != NULL) {
// 访问根节点...
preOrder(t->leftChild); // 访问左子树
preOrder(t->rightChild); // 访问右子树
}
}
中序遍历
template<class T>
void inOrder(binaryTreeNode<T>* t) {
if (t != NULL) {
inOrder(t->leftChild); // 访问左子树
// 访问根节点...
inOrder(t->rightChild); // 访问右子树
}
}
非递归实现
这是
avl树的中序遍历, 偷懒一下
void AVLTree::inOrder() const {
stack<AVLNode*> s;
AVLNode* t = root;
while (t || !s.empty()) {
while (t) {
s.push(t);
t = t->left;
}
t = s.top();
s.pop();
cout << t->key << " ";
t = t->right;
}
}
后序遍历
template<class T>
void postOrder(binaryTreeNode<T>* t) {
if (t != NULL) {
postOrder(t->leftChild); // 访问左子树
postOrder(t->rightChild); // 访问右子树
// 访问根节点...
}
}
层次遍历
从顶层到底层, 从左到右
template<class T>
void levelOrder(binaryTreeNode<T>* t) {
queue<binaryTreeNode<T>*> q;
while (t != NULL) {
// 访问节点...
if (t->leftChild != NULL) {
q.push(t->leftChild);
}
if (t->rightChild != NULL) {
q.push(t->rightChild);
}
if (q.empty()) break; // 如果队空就退出
t = q.front();
q.pop();
}
}
📢 获取高度
层次遍历法
template<class T>
int getHeight(binaryTreeNode<T>* t) {
if (t == NULL) return 0;
queue<binaryTreeNode<T>*> q;
int levelSize = 1; // 当前层的节点数(根节点)
int height = 0; // 树的高度(从零开始, 一层结束就+1)
q.push(t);
while (!q.empty()) {
temp = q.front();
q.pop();
if (temp->leftChild != NULL) {
q.push(t->leftChild);
}
if (temp->rightChild != NULL) {
q.push(t->rightChild);
}
levelSize--; // 访问过元素减一
if (levelSize == 0) {
height++;
levelSize = q.size(); // 下一层的元素个数
}
}
return height;
}
递归法
template<class T>
int getHeight(binaryTreeNode<T>* t) {
if (t == NULL) return 0;
int h1 = getHeight(t->leftChild);
int h2 = getHeight(t->rightChild);
// 子树最大高度加根节点
return h1 > h2 ? ++h1 : ++h2;
}
🌈 获取最大宽度
template<class T>
int getMaxWidth(binaryTreeNode<T>* t) {
if (t == NULL) return 0;
queue<binaryTreeNode<T>*> q;
int maxWidth = 1, levelSize = 1;
q.push(t);
while (!q.empty()) {
temp = q.front();
q.pop();
if (temp->leftChild != NULL) {
q.push(t->leftChild);
}
if (temp->rightChild != NULL) {
q.push(t->rightChild);
}
levelSize--;
if (levelSize == 0) {
levelSize = q.size();
maxWidth = maxWidth > levelSize ? maxWidth : levelSize;
}
}
return maxWidth;
}
递归操作需要栈空间 , 层次遍历需要队列空间
完整代码
#include<queue>
// 节点类
template<class T>
struct binaryTreeNode {
T element; // 数据
// 左右子节点
binaryTreeNode<T>* leftChild, * rightChild;
// 构造函数
binaryTreeNode() {
leftChild = rightChild = NULL;
}
binaryTreeNode(const T& theElement) {
element(theElement);
leftChild = rightChild = NULL;
}
binaryTreeNode(const T& theElement,
binaryTreeNode* leftChild,
binaryTreeNode* rightChild)
{
element(theElement);
this->leftChild = leftChild;
this->rightChild = rightChild;
}
};
// 二叉树
template<class T>
class binaryTree {
public:
virtual ~binaryTree() {}
virtual bool empty() const = 0;
virtual int size() const = 0;
virtual void preOrder(void(*) (T*)) = 0;
virtual void inOrder(void(*) (T*)) = 0;
virtual void postOrder(void(*) (T*)) = 0;
virtual void levelOrder(void(*) (T*)) = 0;
};
// 链表二叉树
template<class T>
class linkedBinaryTree : public binaryTree<binaryTreeNode<T>> {
public:
binaryTreeNode<T>* root;
int treeSize;
linkedBinaryTree() {
root = NULL;
treeSize = 0;
}
~linkedBinaryTree() {
erase();
}
bool empty() const {
return treeSize == 0;
}
int size() const {
return treeSize;
}
// 遍历方法, 传入一个函数(theVisit)的指针
void preOrder(void(*theVisit)(binaryTreeNode<T>*)) {
visit = theVisit;
preOrder(root);
}
void inOrder(void(*theVisit)(binaryTreeNode<T>*)) {
visit = theVisit;
inOrder(root);
}
void postOrder(void(*theVisit)(binaryTreeNode<T>*)) {
visit = theVisit;
postOrder(root);
}
void levelOrder(void(*theVisit)(binaryTreeNode<T>*)) {
visit = theVisit;
levelOrder(root);
}
// 删除二叉树
void erase() {
postOrder(dispose);
root = NULL;
treeSize = 0;
}
// 遍历输出二叉树节点
void preOrderOutput() {
preOrder(output);
cout << endl;
}
void inOrderOutput() {
inOrder(output);
cout << endl;
}
void postOrderOutput() {
postOrder(output);
cout << endl;
}
int height() const {
return height(root);
}
private:
static void (*visit)(binaryTreeNode<T>*);
static void preOrder(binaryTreeNode<T>* t);
static void inOrder(binaryTreeNode<T>* t);
static void postOrder(binaryTreeNode<T>* t);
static void levelOrder(binaryTreeNode<T>* t);
static void dispose(binaryTreeNode<T>* t) {
delete t;
}
static void output(binaryTreeNode<T>* t) {
cout << "节点数据" << t->element << endl;
}
int height(binaryTreeNode<T>* t);
};
// 获取二叉树高度
template<class T>
inline int linkedBinaryTree<T>::height(binaryTreeNode<T>* t) {
if (t == NULL) return 0;
int h1 = height(t->leftChild);
int h2 = height(t->rightChild);
return h1 > h2 ? ++h1 : ++h2;
}
// 前序遍历
template<class T>
void linkedBinaryTree<T>::preOrder(binaryTreeNode<T>* t) {
if (t != NULL) {
linkedBinaryTree<T>::visit(t);
preOrder(t->leftChild); // 访问左子树
preOrder(t->rightChild); // 访问右子树
}
}
// 中序遍历
template<class T>
inline void linkedBinaryTree<T>::inOrder(binaryTreeNode<T>* t) {
if (t != NULL) {
inOrder(t->leftChild); // 访问左子树
linkedBinaryTree<T>::visit(t);
inOrder(t->rightChild); // 访问右子树
}
}
// 后续遍历
template<class T>
inline void linkedBinaryTree<T>::postOrder(binaryTreeNode<T>* t) {
if (t != NULL) {
postOrder(t->leftChild); // 访问左子树
postOrder(t->rightChild); // 访问右子树
linkedBinaryTree<T>::visit(t);
}
}
// 层次遍历
template<class T>
inline void linkedBinaryTree<T>::levelOrder(binaryTreeNode<T>* t) {
queue<binaryTreeNode<T>*> q;
while (t != NULL) {
linkedBinaryTree<T>::visit(t);
if (t->leftChild != NULL) {
q.push(t->leftChild);
}
if (t->rightChild != NULL) {
q.push(t->rightChild);
}
if (q.empty()) break; // 如果队空就退出
t = q.front();
q.pop();
}
}
先序遍历转后序遍历(递归)
仅完全二叉树(或满二叉树)可用
#include<iostream>
#include<string>
using namespace std;
int len = 0, index = 0;
// 前序字符串生成完全二叉树
void makeTree(int x, const string& pre, string& tree) {
if (x > len) return;
tree[x] = pre[index++];
makeTree(x * 2, pre, tree);
makeTree(x * 2 + 1, pre, tree);
}
// 后序遍历
void postOrder(int x, const string& tree, string& pos) {
if (x > len) return;
postOrder(x * 2, tree, pos);
postOrder(x * 2 + 1, tree, pos);
pos[index++] = tree[x];
}
// 前序字符串转后序字符串
string preToPost(const string& pre) {
len = pre.length();
string tree(len + 1, '0');
string pos(len, '0');
index = 0;
makeTree(1, pre, tree);
index = 0;
postOrder(1, tree, pos);
index = 0;
return pos;
}
int main() {
string pre;
cin >> pre;
string pos = preToPost(pre);
for (int i = 0; i < pos.length(); i++) {
cout << pos[i];
}
return 0;
}
先序和中序求树的高度
#include<iostream>
#include<string>
using namespace std;
/*
* @param root: 根节点在先序遍历中的索引
* @param child: 子树在中序中的起始位置
* @param nums: 节点数
*/
int height(const string& pre, const string& in, int root, int child, int nums) {
if (nums != 0) {
// 节点数不为 0
// 查找根节点在中序遍历中的索引
int n = 0;
for (int i = child; i < nums + child; i++) {
if (in[i] == pre[root]) break;
n++;
}
// 左子树根 = root(根节点) + 1(左子树根)
// 左子树起始 = child(当前树起始)
int left = height(pre, in, root + 1, child, n);
// 右子树剩余节点 = nums - n(左子树节点) - 1(根节点)
// 右子树根 = root(根节点位置) + n(左子树节点个数) + 1(右子树根)
// 右子树起始 = child(当前子树起始) + n(左子树个数) + 根(1)
int right = height(pre, in, root + n + 1, child + n + 1, nums - n - 1);
return left > right ? left + 1 : right + 1;
}
else {
return 0;
}
}
int main() {
string pre = "ABDGHCEIF";
string in = "GDHBAEICF";
cout << height(pre, in, 0, 0, 9);
return 0;
}