文章目录
1.概念
- 二叉树,每个节点最多有两个“叉”,也就是两个子节点,分别是左子节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点
- 满二又树,叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点。
- 完全二叉树,叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大。
2.存储方式
2.1 链式存储(二叉树代码大部分是链式实现的)
2.2 顺序存储(基于数组)
- 把根节点存储在下标 i = 1 的位置,那左子节点存储在下标 2 * i = 2 的位置,右子节点存储在 2 * i + 1 = 3 的位置。
- 以此类推,B节点的左子节点存储在 2 * i = 2 * 2 = 4 的位置,右子节点存储在 2 * i + 1 = 2 * 2 + 1 = 5 的位置。
堆排序中的堆就是完全二叉树。
3.二叉树的遍历
void preOrder(Node* root)
{
if(root==NULL)
return;
print root; //打印root节点
preOrder(root->1eft);
preOrder(root->right);
}
void inorder(Node* root)
{
if(root==NULL)
return;
inorder(root->1eft);
print root; //打印root节点
inorder(root->right);
}
void postorder(Node* root)
{
if(root==NULL)
return;
postorder(root->1eft);
postorder(root->right);
print root; //打印root节点
}
void levelorder(Node* root) //按层从左至右打印
{
if(root==NULL)
return;
queue<node*> nodeQueue
nodequeue.push(root);
while(!nodequeue.empty()) //建立节点队列,打印父节点,入队左右子节点,出队父节点
{
node* p = nodeQueue.front();
cout << p->data << " ";
if(p->left != NULL)
nodeQueue.push(p->left);
if(p->right != NULL)
nodeQueue.push(p->right);
nodeQueue.pop();
}
}
每个节点最多会被访问 2 次, 所以遍历操作的时间复杂度, 跟节点的个数 n 成正比,二叉树遍历的时间复杂度是 O(n)
3.1 基于链表的二叉树实现代码
/**
* @description: 二叉树,链表实现
* @author: michael ming
* @date: 2019/5/11 18:03
* @modified by:
*/
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
template <class T>
struct node
{
T data;
node<T> *left, *right;
node<T>():left(NULL), right(NULL){}
};
template <class T>
class binary_tree
{
private:
int nodelen;
node<T> *root;
public:
binary_tree():nodelen(0), root(NULL){}
node<T>* getRoot()const
{
return root;
}
node<T>* insert(node<T> * nodep, size_t lv, size_t toplv, int data = 1)
{
if(lv == 0)
return NULL;
else if(nodep == NULL && lv == toplv)
{
root = new node<T>();
nodep = root;
}
else
{
nodep = new node<T>();
}
nodep->data = data;
nodelen++;
node<T>* l = insert(nodep->left, lv-1, toplv, 2*data);
if(l)
nodep->left = l; //返回创建好的left节点l,跟父接上
node<T>* r = insert(nodep->right, lv-1, toplv, 2*data+1);
if(r)
nodep->right = r; //返回创建好的right节点r,跟父接上
return nodep;
}
void preOrderPrint(node<T> * nodep)
{
if (nodep == NULL)
return;
cout << nodep->data << " ";
preOrderPrint(nodep->left);
preOrderPrint(nodep->right);
}
void inOrderPrint(node<T> * nodep)
{
if (nodep == NULL)
return;
inOrderPrint(nodep->left);
cout << nodep->data << " ";
inOrderPrint(nodep->right);
}
void postOrderPrint(node<T> * nodep)
{
if (nodep == NULL)
return;
postOrderPrint(nodep->left);
postOrderPrint(nodep->right);
cout << nodep->data << " ";
}
void levelOrderPrint(node<T> * nodep) //按层打印
{
if (nodep == NULL)
return;
queue<node<T>*> nodequeue;
nodequeue.push(nodep);
while(!nodequeue.empty()) //建立节点队列,打印父节点,入队左右子节点,出队父节点
{
node<T>* p = nodequeue.front();
cout << p->data << " ";
if(p->left != NULL)
nodequeue.push(p->left);
if(p->right != NULL)
nodequeue.push(p->right);
nodequeue.pop();
}
}
void destory_tree(node<T> * nodep)
{
if (nodep == NULL)
return;
destory_tree(nodep->left);
destory_tree(nodep->right);
delete nodep;
}
//-----------------求二叉树高度-----------------------
int get_height(node<T>* nodep) //递归法, 求左右子树高度,较大的+1
{
if(nodep == NULL)
return 0;
int leftheight = get_height(nodep->left);
int rightheight = get_height(nodep->right);
return max(leftheight, rightheight) + 1;
}
int level_get_height(node<T>* nodep) //按层计算高度
{
if (nodep == NULL)
return 0;
queue<node<T>*> nodequeue;
node<T>* p = NULL;
nodequeue.push(nodep);
int height = 0;
while(!nodequeue.empty()) //建立节点队列,入队左右子节点,出队父节点
{
height++;
int n = nodequeue.size();
for(int i = 0; i < n; ++i)
{
p = nodequeue.front();
if(p->left != NULL)
nodequeue.push(p->left);
if(p->right != NULL)
nodequeue.push(p->right);
nodequeue.pop();
}
}
return height;
}
int stack_get_height(node<T>* nodep) //用栈实现前序(或后序)遍历,最大栈长度即为树的高度
{
if (nodep == NULL)
return 0;
stack<node<T>*> nodestack;
node<T> *temp = NULL;
int height = 0;
while(nodep != NULL || !nodestack.empty())
{
if(nodep != NULL)
{
nodestack.push(nodep);
nodep = nodep->left;//找到最底端左节点
}
else
{
nodep = nodestack.top();//最底端左节点的父节点nodep
if(nodep->right != NULL && nodep->right != temp) //右边有节点,且没有进过栈
nodep = nodep->right; //进入右节点,跳到上个if查其子树
else //没有子节点,或者子节点进过栈
{
if(nodestack.size() > height)
height = nodestack.size(); //更新最大高度
temp = nodep; //记录弹栈的节点到temp
nodestack.pop();
nodep = NULL;
}
}
}
return height;
}
};
int main()
{
binary_tree<int> btree;
btree.insert(btree.getRoot(), 3, 3);
btree.preOrderPrint(btree.getRoot());
cout << endl << endl;
btree.inOrderPrint(btree.getRoot());
cout << endl << endl;
btree.postOrderPrint(btree.getRoot());
cout << endl << endl;
btree.levelOrderPrint(btree.getRoot());
cout << endl;
cout << "height of tree: " << btree.get_height(btree.getRoot()) << endl;
cout << "level height of tree: " << btree.level_get_height(btree.getRoot()) << endl;
cout << "stack height of tree: " << btree.stack_get_height(btree.getRoot()) << endl;
btree.destory_tree(btree.getRoot());
return 0;
}
3.2 基于数组的二叉树实现代码
/**
* @description: 二叉树,数组实现
* @author: michael ming
* @date: 2019/5/11 11:44
* @modified by:
*/
#include <iostream>
using namespace std;
template <class T>
struct node
{
T data;
node<T>(){}
};
template <class T>
class binary_tree
{
private:
int size;
size_t tree_arrlen;
node<T>* tree;
public:
binary_tree(int len = 20):size(len),tree_arrlen(0)
{
tree = new node<T> [size];
}
~binary_tree()
{
delete [] tree;
}
void insert(T &data)
{
if(tree_arrlen < size)
tree[++tree_arrlen].data = data;
}
void preOrderPrint(size_t index = 1)
{
if(tree_arrlen < 1 || index > tree_arrlen)
return;
cout << tree[index].data << " ";
preOrderPrint(index*2);
preOrderPrint(index*2+1);
}
void inOrderPrint(size_t index = 1)
{
if(tree_arrlen < 1 || index > tree_arrlen)
return;
inOrderPrint(index*2);
cout << tree[index].data << " ";
inOrderPrint(index*2+1);
}
void postOrderPrint(size_t index = 1)
{
if(tree_arrlen < 1 || index > tree_arrlen)
return;
postOrderPrint(index*2);
postOrderPrint(index*2+1);
cout << tree[index].data << " ";
}
};
int main()
{
binary_tree<int> btree;
for(int i = 1; i < 8; ++i)
btree.insert(i);
btree.preOrderPrint();
cout << endl;
btree.inOrderPrint();
cout << endl;
btree.postOrderPrint();
return 0;
}
3.3 非递归法 二叉树遍历
- 前序(入栈root,访问stack.top(), 出栈,依次入栈右节点,左节点)
void stackPreOrder()
{
stack<node<T>*> nodeStack;
node<T> * nodep = root;
if(nodep != NULL)
{
nodeStack.push(nodep);
while(!nodeStack.empty())
{
nodep = nodeStack.top();
nodeStack.pop();
cout << nodep->data << " ";
if(nodep->right != NULL) //注意左右节点入栈顺序!!!
nodeStack.push(nodep->right);
if(nodep->left != NULL)
nodeStack.push(nodep->left);
}
}
}
- 中序(入栈右、根、(左的右、左的根、…),左右节点为空,到达叶子节点,打印叶子节点,)
void stackInOrder()
{
stack<node<T>*> nodeStack;
node<T> *nodep = root;
while(nodep != NULL)
{
while(nodep != NULL)//入栈右、根
{
if(nodep->right)
nodeStack.push(nodep->right);
nodeStack.push(nodep);
nodep = nodep->left;
}
nodep = nodeStack.top();//根节点
nodeStack.pop();
while(!nodeStack.empty() && nodep->right == NULL)//nodep为叶子节点
{
cout << nodep->data << " ";//打印叶子节点
nodep = nodeStack.top();
nodeStack.pop();
}
cout << nodep->data << " ";//左节点为空,右节点非空or最后一个节点
if(!nodeStack.empty())
{
nodep = nodeStack.top();
nodeStack.pop();
}
else
nodep = NULL;
}
}
- 后序
void stackPostOrder()
{
stack<node<T>*> nodeStack;
node<T> *nodep = root, *temp = root;
while(nodep != NULL)
{
for(;nodep->left != NULL; nodep = nodep->left)
nodeStack.push(nodep); //入栈一路上的左节点
while(nodep->right == NULL || nodep->right == temp)
{
cout << nodep->data << " ";//打印叶子节点
temp = nodep;
if(nodeStack.empty())
return;
nodep = nodeStack.top();//回到父节点
nodeStack.pop();
}
nodeStack.push(nodep);
nodep = nodep->right;//转到右子树
}
}