数据结构专题——二叉树的存储结构与基本操作

一般来说,二叉树使用链表来定义。

与普通链表的差别在于,二叉树每个节点有两条出边,因此指针域变成了两个,分别指向左子树根节点地址和右子树的根节点地址,如果某个子树不存在,则指向NULL,其他地方与普通链表完全相同,这样的链表又被叫作二叉链表。

  • 二叉树数据结构的定义
struct node{
    typename data;    //typename是数据的类型
    node* lchild;    //指向左子树根节点的指针
    node* rchild;    //指向右子树根节点的指针
}

由于二叉树的根节点一开始不存在,所以一开始定义为

node* root = NULL;
  • 新建二叉树节点

如果需要新建节点,可以使用如下方式:

node* createNode(int v){
    node* Node = new node;    //申请节点空间
    Node->data = v;           //节点权值为v 
    Node->lchild = NULL;      //将左子树指针置为NULL
    Node->rchild = NULL;      //将右子树指针置为NULL
    return Node;              //返回新建节点的地址
}
  • 二叉树节点的查找、修改
//采用递归方式来实现树的查找,因此存在递归式与递归边界
//此处树节点中所存储的数据假设为int型,可类推其他数据类型
void searchNode(node* root,int x,int newdata){
    if(root==NULL){
        return;    //空树,死胡同(递归边界)
    }
    if(root->data==x){    //找到值为x的节点,把它修改为newdata
        root->data=newdata;
    }
    serachNode(root->lchild,x,newdata);    //往左子树搜索x(递归式)
    searchNode(root->rchild,x,newdata);    //往右子树搜索x(递归式)
}
  • 二叉树的插入

二叉树新节点的插入需要根据具体的背景条件来决定应该插入在什么位置。

此处举一个较为通用的例子:

//insert函数在二叉树中插入一个值为x的节点
void insertNode(node* &root,int x){    //此处必须加上&,使得可以实际的改变指针root的值
    if(root==NULL){
        root=creatNode(x);
    }
    if(根据条件应该将节点插入在左子树){
        insertNode(root->lchild,x);
    }
    else{//根据条件应该插入右子树
        insertNode(root->rchild,x);
    }
}
  • 二叉树的创建

因为二叉树的insertNode函数中已经包含了二叉树新节点的插入规则,因此只需将数据依次输入,即可创建二叉树。

//二叉树的建立
//此处仍然以data类型为int举例
node* createTree(int data[],int n){
    node* root = NULL;    //创建空的根节点root
    for(int i = 0; i < n; i++){
        insertNode(root,x);
    }   
    return root;    //返回根节点 
}

另外,除了以二叉链表的形式来表示树,对于完全二叉树,也可以用数组的形式来表示:

我们将完全二叉树的根节点记为1,其左子树和右子树依次记为2和3,由这样的规则一次排下去标记这棵树,可以发现这样的一个规律:

完全二叉树中一个节点的标号为x,则其左子节点的标号为2x,右子节点标号为2x+1.因此可以建立一个2^{^{k}}大小的数组来记录这一颗完全二叉树。若已知该完全二叉树,也可以节点总个数+1来创建该数组。

对于这种存储方式,还有一些特点:

  1. 该数组元素存放顺序恰好为该完全二叉树的层序遍历序列。
  2. 判断某个节点是否为叶节点的标志是:该节点的左子节点的标号2x是否大于节点总个数n。
  3. 判断摸个节点是否为空节点的标志位:该节点的标号是否大于节点总个数n。

你可能感兴趣的:(数据结构专题)