1 二叉树定义
- 逻辑结构:树形结构——二叉树
- 存储结构:链式存储结构
C++:
struct node
{
ElemType data;//数据域
node* lchild;//左孩子指针
node* rchild; //右孩子指针
ElemType layer; //层次
};
C:
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode;
2 基本操作
- 1新建
- 1.1 新建结点
//新建结点
node* newNode(ElemType v){
node* Node = new node;//C++
//BTNode *Node;
//Node = (BTNode*)malloc(sizeof(BTNode)); //C写法
Node->data = v;
Node->lchild = Node->rchild = NULL;
return Node;
}
- 1.2 增加新结点
//增加新结点
void Insert(node* &root, ElemType x){//对二叉树结构作出修改(新建结点),需要加引用
//只修改当前已有结点的内容/遍历树,无需加引用
if(root == NULL){
root = newNode(x);
return;
}
if(由二叉树的性质,x应该插在左子树){
Insert(root->lchild, x);
}else{
Insert(root->rchild, x);
}
}
- 1.3 新建树
//新建树
node* Create(int data[], int n){
node* root = new node;
for (int i = 0; i < n; ++i)
{
Insert(root, data[i]);
}
return root;
}
- 1.4 根据中序和前序创建二叉树
//前序、中序创建二叉树
node* Create2(int preL, int preR, int inL, int inR){
if(preL > preR){
return NULL;
}
node* root = new node;
root->data = pre[preL];
int k;
for (k = inL; k <= inR; ++k)
{
if(in[k] == root->data){
break;
}
}
int numLeft = k - inL;
root->lchild = Create2(preL + 1, preL + numLeft, inL, k - 1);
root->rchild = Create2(preL + numLeft + 1, preR, k + 1, inR);
return root;
}
1.5 根据后序和中序创建二叉树
node* Create3(int postL, int postR, int inL, int inR){
if(postL > postR){
return NULL;
}
node* root = new node;
root->data = post[postR];
int k;
for (k = inL; k <= inR; ++k) {
if(in[k] == root->data){
break;
}
}
int numLeft = k - inL;
root->lchild = Create3(postL, postL + numLeft - 1, inL, k - 1);
root->rchild = Create3(postL + numLeft, postR - 1, k + 1, inR);
return root;
}
1.6 根据层序、中序建立二叉树
node* Create4(vector<int> layer, int inL, int inR){
if(layer.size() == 0){//当前层序遍历完
return NULL;
}
node* root = new node;
root->data = layer[0];
int k;
for (k = inL; k <= inR; ++k) {//中序序列中寻找根结点
if(in[k] == root->data){
break;
}
}
vector<int> leftLayer;//左子树层次遍历
vector<int> rightLayer;//右子树层次遍历
for (int i = 1; i < layer.size(); ++i) {//遍历层序序列,分左右子树存储
bool isLeft = false;
for (int j = inL; j < k; ++j) {
if(layer[i] == in[j]){
isLeft = true;
break;
}
}
if(isLeft == true){
leftLayer.push_back(layer[i]);
}else{
rightLayer.push_back(layer[i]);
}
}
root->lchild = Create4(leftLayer,inL, k - 1);
root->rchild = Create4(rightLayer,k + 1, inR);
return root;
}
- 2 修改结点
//修改结点
void Search(node* root, ElemType x, ElemType newdata){//结点
//递归边界
if(root == NULL){//空树、死胡同
return;
}
if(root->data == x){//找到数据域为x的结点,把它修改为,
root->data = newdata;
}
//递归式
Search(root->lchild, x, newdata);//往左子树搜索x
Search(root->rchild, x, newdata);//往右子树搜索x
}
-
3 遍历二叉树
- 3.1前序
-
递归:
void preorder(node* root){//前序
if(root == NULL){
return;
}
printf("%d\n", root->data);
preorder(root->lchild);
preorder(root->rchild);
}
- 非递归
- 前中后序的非递归遍历均需借助栈来实现
void preorder2(node* root){
stack<node*> s;
node* p = root;//遍历指针
while(p || !s.empty()){//如果p非空或栈非空
if(p){//根指针进栈,遍历左子树
printf("%d\n", p->data);
s.push(p);//每次遇到非空二叉树,先向左走
p = p->lchild;
}else{//根指针退栈,遍历右子树
p = s.top();
s.pop();
p = p->rchild;
}
}
}
- 3.2中序
- 递归
void inorder(node* root){//中序
if(root == NULL){
return;
}
inorder(root->lchild);
printf("%d\n", root->data);
inorder(root->rchild);
}
- 非递归
void inorde2(node* root){
stack<node*> s;
node* p = root;//遍历指针
while(p || !s.empty()){//如果p非空或栈非空
if(p){ //根指针进栈,遍历左子树
s.push(p); //每次遇到非空二叉树,先向左走
p = p->lchild;
}else{//根指针退栈,访问根结点,遍历右子树
p= s.top();
s.pop();//退栈,访问根结点
printf("%d\n", p->data);
p = p->rchild;
}
}
}
- 3.3后序
- 递归
void postorder(node* root){//后序
if(root == NULL){
return;
}
postorder(root->lchild);
postorder(root->rchild);
printf("%d\n", root->data);
}
- 非递归
- 注意:
- 后序遍历,是先访问左子树,再访问右子树,最后访问根结点。用堆栈存储结点时,必须分清返回根结点时,是从左子树返回还是从右子树返回。所以使用辅助指针记录最近访问过的结点。需要判断上次访问的节点是位于左子树,还是右子树。
- 注意:
void postorder2(node* root){
stack<node*> s;
node* p = root;
node* r = NULL;//辅助指针啊,指向最近访问过的结点
while(p || !s.empty()){
if(p){ //走到最左边
s.push(p);
p = p->lchild;
}else{ //向右
p = s.top();//取栈顶指针
if(p->rchild && p->rchild != r){//若右子树存在,且未被访问过
p = p->rchild; //转向右子树
s.push(p); //压入栈
p = p->lchild; //再走向最左
}else{//右子树同时为空时,弹出
s.pop();
printf("%d\n", p->data);//弹出结点,并访问
r = p; //记录最近访问过的结点
p = NULL;//结点访问完后,重置p指针
}
}
}
}
- 3.4层序
void LayerOrder2(node* root){//层序遍历
queue<node*> q;
root->layer= 1;
q.push(root);//将根结点地址进入地址
while(!q.empty()){
node* now = q.front();//取出队首元素
q.pop();
printf("%d\n", now->data);//访问队首元素
if(now->lchild != NULL){
now->lchild->layer = now->layer + 1;
q.push(now->lchild);//左子树非空
}
if(now->rchild != NULL){
now->rchild->layer = now->layer + 1;
q.push(now->rchild);//右子树非空
}
}
}
4 二叉树静态实现
- 4.1 定义
const int MAXN = 6;
typedef int Elemtype;
struct node
{
Elemtype data;//数据域
int left; //指向左子树的指针域
int right; //指向右子树的指针域
}Node[MAXN];//结点数组
- 4.2 新建
//新建结点
int Index = 0;
int newNode(int v){//分配一个Node数组中的结点给新结点,index为新下表
Node[Index].data = v;
Node[Index].left = -1;
Node[Index].right = -1;
return Index++;
}
- 4.3 查改
//查找并修改
void Search(int root, int x, int newdata){//root为根结点在数组中的下表
if(root == -1){
return;//递归边界:空树
}
if(Node[root].data == x){
Node[root].data = newdata;
}
//递归式:往左右子树搜索x
Search(Node[root].left, x, newdata);
Search(Node[root].right, x, newdata);
}
- 4.4 插入结点
//插入
void Insert(int &root, int x){
if(root == -1){
root = newNode(x);
return;
}
if(1 == 1){//根据二叉树的性质,应该插在左子树
Insert(Node[root].left, x);
}else{
Insert(Node[root].right, x);
}
}
- 4.5 创建
int Create(int data[], int n){
int root = -1;//新建根结点
for (int i = 0; i < n; ++i)
{
Insert(root, data[i]);
}
return root;//返回二叉树根结点下标
}
- 4.7 前序
void preOrder(int root){
if(root == -1){
return;
}
printf("%d\n", Node[root].data);
preOrder(Node[root].left);
preOrder(Node[root].right);
}
- 4.8 中序
void inOrder(int root){
if(root == -1){
return;
}
inOrder(Node[root].left);
printf("%d\n", Node[root].data);
inOrder(Node[root].right);
}
- 4.9 后序
void postOrder(int root){
if(root == -1){
return;
}
postOrder(Node[root].left);
postOrder(Node[root].right);
printf("%d\n", Node[root].data);
}
4.10 层序
void layerOrder(int root){
queue<int > q;//定义队列
q.push(root);//根结点入队
while(!q.empty()){
int now = q.front();//取出队首元素
q.pop();
printf("%d\n", Node[now].data);//访问队首元素
if(Node[now].left != -1){
q.push(Node[now].left);
}
if(Node[now].right != -1){
q.push(Node[now].right);
}
}
}
5 完整测试代码
- 链式二叉树
#include <cstdio>
#include <queue>
#include <stack>
#include <vector>
using std::queue;
using std::stack;
using std::vector;
typedef int ElemType;
struct node
{
ElemType data;//数据域
node* lchild;//左孩子指针
node* rchild; //右孩子指针
ElemType layer; //层次
};
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode;
//新建结点
node* newNode(ElemType v){
node* Node = new node;
//BTNode *BT = (BTNode*)malloc(sizeof(BTNode)); //C写法
Node->data = v;
Node->lchild = Node->rchild = NULL;
return Node;
}
//修改结点
void Search(node* root, ElemType x, ElemType newdata){//结点
//递归边界
if(root == NULL){//空树、死胡同
return;
}
if(root->data == x){//找到数据域为x的结点,把它修改为,
root->data = newdata;
}
//递归式
Search(root->lchild, x, newdata);//往左子树搜索x
Search(root->rchild, x, newdata);//往右子树搜索x
}
//增加新结点
void Insert(node* &root, ElemType x){//对二叉树结构作出修改(新建结点),需要加引用
//只修改当前已有结点的内容/遍历树,无需加引用
if(root == NULL){
root = newNode(x);
return;
}
if(1 == 1){//由二叉树的性质,x应该插在左子树
Insert(root->lchild, x);
}else{
Insert(root->rchild, x);
}
}
//新建树
node* Create(int data[], int n){
node* root = new node;
for (int i = 0; i < n; ++i)
{
Insert(root, data[i]);
}
return root;
}
void preorder(node* root){//前序
if(root == NULL){
return;
}
printf("%d\n", root->data);
preorder(root->lchild);
preorder(root->rchild);
}
void preorder2(node* root){
stack<node*> s;
node* p = root;
while(p || !s.empty()){
if(p){
printf("%d\n", p->data);
s.push(p);
p = p->lchild;
}else{
p = s.top();
s.pop();
p = p->rchild;
}
}
}
void inorder(node* root){//中序
if(root == NULL){
return;
}
inorder(root->lchild);
printf("%d\n", root->data);
inorder(root->rchild);
}
void inorde2(node* root){
stack<node*> s;
node* p = root;//遍历指针
while(p || !s.empty()){//如果p非空或栈非空
if(p){ //根指针进栈,遍历左子树
s.push(p); //每次遇到非空二叉树,先向左走
p = p->lchild;
}else{//根指针退栈,访问根结点,遍历右子树
p= s.top();
s.pop();//退栈,访问根结点
printf("%d\n", p->data);
p = p->rchild;
}
}
}
void postorder(node* root){//后序
if(root == NULL){
return;
}
postorder(root->lchild);
postorder(root->rchild);
printf("%d\n", root->data);
}
void postorder2(node* root){
stack<node*> s;
node* p = root;
node* r = NULL;//辅助指针啊,指向最近访问过的结点
while(p || !s.empty()){
if(p){ //走到最左边
s.push(p);
p = p->lchild;
}else{ //向右
p = s.top();//取栈顶指针
if(p->rchild && p->rchild != r){//若右子树存在,且未被访问过
p = p->rchild; //转向右子树
s.push(p); //压入栈
p = p->lchild; //再走向最左
}else{//右子树同时为空时,弹出
s.pop();
printf("%d\n", p->data);//弹出结点,并访问
r = p; //记录最近访问过的结点
p = NULL;//结点访问完后,重置p指针
}
}
}
}
void LayerOrder(node* root){//层序遍历
queue<node*> q;
q.push(root);//将根结点地址进入地址
while(!q.empty()){
node* now = q.front();//取出队首元素
q.pop();
printf("%d\n", now->data);//访问队首元素
if(now->lchild != NULL){
q.push(now->lchild);//左子树非空
}
if(now->rchild != NULL){
q.push(now->rchild);//右子树非空
}
}
}
void LayerOrder2(node* root){//层序遍历
queue<node*> q;
root->layer= 1;
q.push(root);//将根结点地址进入地址
while(!q.empty()){
node* now = q.front();//取出队首元素
q.pop();
printf("%d\n", now->data);//访问队首元素
if(now->lchild != NULL){
now->lchild->layer = now->layer + 1;
q.push(now->lchild);//左子树非空
}
if(now->rchild != NULL){
now->rchild->layer = now->layer + 1;
q.push(now->rchild);//右子树非空
}
}
}
int pre[] = {1,2,3,4,5,6};
int in[] = {3,2,1,5,4,6};
//前序、中序创建二叉树
node* Create2(int preL, int preR, int inL, int inR){
if(preL > preR){//先序序列小于等于0时,返回
return NULL;
}
node* root = new node;//寻找根结点,存放当前二叉树根结点
root->data = pre[preL];
int k;
for (k = inL; k <= inR; ++k)//寻找根结点
{
if(in[k] == root->data){
break;
}
}
int numLeft = k - inL;//左子树的结点个数
root->lchild = Create2(preL + 1, preL + numLeft, inL, k - 1);
root->rchild = Create2(preL + numLeft + 1, preR, k + 1, inR);
return root;
}
int post[] = {3,2,5,6,4,1};
//后序、终序创建二叉树
node* Create3(int postL, int postR, int inL, int inR){
if(postL > postR){//后序序列小于等于0时,返回
return NULL;
}
node* root = new node;//新建一个结点,存放当前二叉树根结点
root->data = post[postR];
int k;
for (k = inL; k <= inR; ++k) {//中序序列中寻找根结点
if(in[k] == root->data){
break;
}
}
int numLeft = k - inL;
root->lchild = Create3(postL, postL + numLeft - 1, inL, k - 1);
root->rchild = Create3(postL + numLeft, postR - 1, k + 1, inR);
return root;
}
//层序、中序创建二叉树
node* Create4(vector<int> layer, int inL, int inR){
if(layer.size() == 0){//当前层序遍历完
return NULL;
}
node* root = new node;
root->data = layer[0];
int k;
for (k = inL; k <= inR; ++k) {//中序序列中寻找根结点
if(in[k] == root->data){
break;
}
}
vector<int> leftLayer;//左子树层次遍历
vector<int> rightLayer;//右子树层次遍历
for (int i = 1; i < layer.size(); ++i) {//遍历层序序列,分左右子树存储
bool isLeft = false;
for (int j = inL; j < k; ++j) {
if(layer[i] == in[j]){
isLeft = true;
break;
}
}
if(isLeft == true){
leftLayer.push_back(layer[i]);
}else{
rightLayer.push_back(layer[i]);
}
}
root->lchild = Create4(leftLayer,inL, k - 1);
root->rchild = Create4(rightLayer,k + 1, inR);
return root;
}
int main(int argc, char const *argv[])
{
node* root;
vector<int> layer;
layer.push_back(1);
layer.push_back(2);
layer.push_back(4);
layer.push_back(3);
layer.push_back(5);
layer.push_back(6);
root = Create4(layer, 0, 5);
//postorder2(root);
inorde2(root);
//preorder2(root);
return 0;
}
参考文献:https://blog.csdn.net/u011240016/article/details/58727082