1. 程式人生 > >資料結構專題——二叉樹的儲存結構與基本操作

資料結構專題——二叉樹的儲存結構與基本操作

一般來說,二叉樹使用連結串列來定義。

與普通連結串列的差別在於,二叉樹每個節點有兩條出邊,因此指標域變成了兩個,分別指向左子樹根節點地址和右子樹的根節點地址,如果某個子樹不存在,則指向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。