二叉树【链式、静态】创建(前中序、后中序、层中序)与基本操作(增查改、前中后层遍历【递归/非递归】)————附C/C++实现代码

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

发布了321 篇原创文章 · 获赞 51 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_33375598/article/details/104113608