隨筆-126  評論-247  文章-5  trackbacks-0

                    
          二叉排序樹 ( Binary  Sort  Tree ) 又稱 二叉查找樹 ( Binary  Search  Tree )。

          它或者是一棵空樹,或者是具有下列性質(zhì)的二叉樹:

          1. 若它的左子樹不空,則左子樹上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值
           
          2. 若它的右子樹不空,則右子樹上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值

          3. 它的左、右子樹也分別為二叉排序樹


          二叉排序樹的查找算法

          在二叉排序樹 T 中查找 V 的過程為:

          1. 若 T 是空樹,則搜索失敗

          2. 若 V 等于 T 的根節(jié)點(diǎn)的數(shù)據(jù)域之值,則查找成功

          3. 若 V 小于 T 的根節(jié)點(diǎn)的數(shù)據(jù)域之值,則搜索 T 的左子樹,否則查找 T 的右子樹


          二叉排序樹查找算法代碼片段


          //查找結(jié)點(diǎn)
          //如果找不到,see 指向最后一個結(jié)點(diǎn),并返回false; 如果找到,see 指向該結(jié)點(diǎn),并返回true
          bool search(Tree root, TNode parent, TNode &see, Element key){
              
          if(!root){
                  see 
          = parent;
                  
          return false;
              }
              
          if(root->data == key){
                  see 
          = root;
                  
          return true;
              }
              
          if(root->data > key){
                  
          return search(root->lchild, root, see, key);
              }
          else{
                  
          return search(root->rchild, root, see, key);
              }
          }

          //重載函數(shù)
          //如果找不到,則返回NULL; 如果找到,則返回該結(jié)點(diǎn)
          TNode search(Tree root, TNode parent, Element key){
              
          if(!root){
                  
          return NULL;
              }
              
          if(root->data == key){
                  
          return root;
              }
              
          if(root->data > key){
                  
          return search(root->lchild, root, key);
              }
          else{
                  
          return search(root->rchild, root, key);
              }
          }

          //重載函數(shù)
          TNode search(Tree root, Element e){
              
          return search(root, NULL, e);
          }
            


          二叉排序樹插入結(jié)點(diǎn)的算法

          向一個二叉查找樹 T 中插入一個結(jié)點(diǎn) S 的過程為:

          1. 若 T 是空樹,則將 S 所指結(jié)點(diǎn)作為根結(jié)點(diǎn)插入

          2. 若 S 的數(shù)據(jù)域的值等于 T 的根結(jié)點(diǎn)的數(shù)據(jù)域之值,說明該結(jié)點(diǎn)已經(jīng)存在,不進(jìn)行插入操作

          3. 若 S 的數(shù)據(jù)域的值小于 T 的根結(jié)點(diǎn)的數(shù)據(jù)域之值,則把 S 所指結(jié)點(diǎn)插入到左子樹中,否則插入到右子樹中

          二叉排序樹插入結(jié)點(diǎn)的算法代碼片段

            
          //二叉排序樹插入結(jié)點(diǎn)
          bool insertNode(Tree &root, Element e){
              TNode parent;
              
          bool isFound = search(root, NULL, parent, e);  //查找該結(jié)點(diǎn)
              if(isFound){  //已經(jīng)存在
                  printf("該結(jié)點(diǎn)已經(jīng)存在,插入操作失敗!");
                  
          return false;
              }
              TNode node 
          = (TNode)malloc(sizeof(Node));
              node
          ->data = e;
              node
          ->lchild = node->rchild = NULL;
              
          if(!parent){ //空樹
                  root = node;
              }
          else{
                  
          if(parent->data > e){
                      parent
          ->lchild = node;
                  }
          else{
                      parent
          ->rchild = node;
                  }
              }
              
          return true;
          }
            


           二叉排序樹刪除結(jié)點(diǎn)的算法

          分三種情況討論:

          1. 若 *current 結(jié)點(diǎn)為葉子結(jié)點(diǎn),即PL(左子樹)和PR(右子樹)均為空樹。由于刪去葉子結(jié)點(diǎn)不破壞整棵樹的結(jié)構(gòu),則只需修改其雙親結(jié)點(diǎn)的指針即可

          2. 若 *current 結(jié)點(diǎn)只有左子樹PL或右子樹PR,此時只要令PL或PR直接成為其雙親結(jié)點(diǎn) *cparent 的左子樹(當(dāng) *current 是左子樹)

          或右子樹(當(dāng) *current 是右子樹)即可,作此修改也不破壞二叉排序樹的特性

          3. 若 *current 結(jié)點(diǎn)的左子樹和右子樹均不空。在刪去 *current 之后,為保持其它元素之間的相對位置不變,可按中序遍歷保持有序進(jìn)行調(diào)整,

          可以有兩種做法:

          其一是令 *current 的左子樹為 *cparent 的左/右(依 *current 是 *cparent 的左子樹還是右子樹而定)子樹,

          *precursor 為 *current 左子樹的最右下的結(jié)點(diǎn),而 *current 的右子樹為 *precursor 的右子樹

          其二是令 *current 的直接前驅(qū)(或直接后繼)替代 *current ,然后再從二叉排序樹中刪去它的直接前驅(qū)(或直接后繼)

           二叉排序樹刪除結(jié)點(diǎn)的算法代碼片段

            
          //刪除二叉排序樹結(jié)點(diǎn)
          void deleteNode(Tree &root, Element key){
              Node 
          *current, *cparent, *del;
              current 
          = root;  //當(dāng)前結(jié)點(diǎn)
              cparent = NULL;  //當(dāng)前結(jié)點(diǎn)的雙親結(jié)點(diǎn)
              del = NULL;      //刪除的結(jié)點(diǎn)
              while(current && current->data != key){  //查找被刪除的結(jié)點(diǎn),可直接調(diào)用上面的search函數(shù)
                  cparent = current;
                  
          if(current->data > key){
                      current 
          = current->lchild;
                  }
          else{
                      current 
          = current->rchild;
                  }
              }
              
          if(!current){  //沒找到
                  printf("刪除的結(jié)點(diǎn)不存在!");
                  
          return ;
              }
              del 
          = current; //找到了
              if(!current->lchild){  //被刪結(jié)點(diǎn)無左子樹,重接右子樹
                  if(current == cparent->lchild)
                      cparent
          ->lchild = current->rchild;
                  
          else
                      cparent
          ->rchild = current->rchild;
              }
          else if(!current->rchild){  //被刪結(jié)點(diǎn)無右子樹,重接左子樹
                  if(current == cparent->lchild)
                      cparent
          ->lchild = current->lchild;
                  
          else
                      cparent
          ->rchild = current->lchild;
              }
          else{  //被刪結(jié)點(diǎn)同時存在左子樹和右子樹
                  Node *precursor, *parent;
                  precursor 
          = current->lchild;  //被刪結(jié)點(diǎn)的直接前驅(qū)結(jié)點(diǎn)
                  parent = current;  //前驅(qū)結(jié)點(diǎn)的雙親結(jié)點(diǎn)
                  while(precursor->rchild){  //查找前驅(qū)結(jié)點(diǎn)(中序遍歷到最后)
                      parent = precursor;
                      precursor 
          = precursor->rchild;
                  }
                  current
          ->data = precursor->data;  //前驅(qū)結(jié)點(diǎn)替換被刪結(jié)點(diǎn)
                  if(parent != current){  //重接右子樹
                      parent->rchild = precursor->lchild;
                  }
          else{  //重接左子樹
                      parent->lchild = precursor->lchild;
                  }
                  del 
          = precursor;
              }
              free(del);  
          //釋放被刪結(jié)點(diǎn)內(nèi)存空間
          }
             


          完整代碼:

            
          /**
           * <!--
           * File   : binarysorttree.h
           * Author : fancy
           * Email  : fancydeepin@yeah.net
           * Date   : 2013-02-04
           * --!>
           
          */
          #include 
          <stdio.h>
          #include 
          <stdlib.h>
          #include 
          <malloc.h>
          #define Element char
          #define format "%c"

          typedef 
          struct Node {
              Element data;
              
          struct Node *lchild;
              
          struct Node *rchild;
          *Tree, *TNode;

          int index = 0;  //全局索引變量

          //二叉樹構(gòu)造器,按先序遍歷順序構(gòu)造二叉樹
          //無左子樹或右子樹用'#'表示
          void treeNodeConstructor(Tree &root, Element data[]){
              Element e 
          = data[index++];
              
          if(e == '#'){
                  root 
          = NULL;
              }
          else{
                  root 
          = (Node *)malloc(sizeof(Node));
                  root
          ->data = e;
                  treeNodeConstructor(root
          ->lchild, data);
                  treeNodeConstructor(root
          ->rchild, data);
              }
          }

          //查找結(jié)點(diǎn)
          //如果找不到,see 指向最后一個結(jié)點(diǎn),并返回false; 如果找到,see 指向該結(jié)點(diǎn),并返回true
          bool search(Tree root, TNode parent, TNode &see, Element key){
              
          if(!root){
                  see 
          = parent;
                  
          return false;
              }
              
          if(root->data == key){
                  see 
          = root;
                  
          return true;
              }
              
          if(root->data > key){
                  
          return search(root->lchild, root, see, key);
              }
          else{
                  
          return search(root->rchild, root, see, key);
              }
          }

          //重載函數(shù)
          //如果找不到,則返回NULL; 如果找到,則返回該結(jié)點(diǎn)
          TNode search(Tree root, TNode parent, Element key){
              
          if(!root){
                  
          return NULL;
              }
              
          if(root->data == key){
                  
          return root;
              }
              
          if(root->data > key){
                  
          return search(root->lchild, root, key);
              }
          else{
                  
          return search(root->rchild, root, key);
              }
          }

          //重載函數(shù)
          TNode search(Tree root, Element e){
              
          return search(root, NULL, e);
          }

          //刪除二叉排序樹結(jié)點(diǎn)
          void deleteNode(Tree &root, Element key){
              Node 
          *current, *cparent, *del;
              current 
          = root;  //當(dāng)前結(jié)點(diǎn)
              cparent = NULL;  //當(dāng)前結(jié)點(diǎn)的雙親結(jié)點(diǎn)
              del = NULL;      //刪除的結(jié)點(diǎn)
              while(current && current->data != key){  //查找被刪除的結(jié)點(diǎn),可直接調(diào)用上面的search函數(shù)
                  cparent = current;
                  
          if(current->data > key){
                      current 
          = current->lchild;
                  }
          else{
                      current 
          = current->rchild;
                  }
              }
              
          if(!current){  //沒找到
                  printf("刪除的結(jié)點(diǎn)不存在!");
                  
          return ;
              }
              del 
          = current; //找到了
              if(!current->lchild){  //被刪結(jié)點(diǎn)無左子樹,重接右子樹
                  if(current == cparent->lchild)
                      cparent
          ->lchild = current->rchild;
                  
          else
                      cparent
          ->rchild = current->rchild;
              }
          else if(!current->rchild){  //被刪結(jié)點(diǎn)無右子樹,重接左子樹
                  if(current == cparent->lchild)
                      cparent
          ->lchild = current->lchild;
                  
          else
                      cparent
          ->rchild = current->lchild;
              }
          else{  //被刪結(jié)點(diǎn)同時存在左子樹和右子樹
                  Node *precursor, *parent;
                  precursor 
          = current->lchild;  //被刪結(jié)點(diǎn)的直接前驅(qū)結(jié)點(diǎn)
                  parent = current;  //前驅(qū)結(jié)點(diǎn)的雙親結(jié)點(diǎn)
                  while(precursor->rchild){  //查找前驅(qū)結(jié)點(diǎn)(中序遍歷到最后)
                      parent = precursor;
                      precursor 
          = precursor->rchild;
                  }
                  current
          ->data = precursor->data;  //前驅(qū)結(jié)點(diǎn)替換被刪結(jié)點(diǎn)
                  if(parent != current){  //重接右子樹
                      parent->rchild = precursor->lchild;
                  }
          else{  //重接左子樹
                      parent->lchild = precursor->lchild;
                  }
                  del 
          = precursor;
              }
              free(del);  
          //釋放被刪結(jié)點(diǎn)內(nèi)存空間
          }

          //二叉排序樹插入結(jié)點(diǎn)
          bool insertNode(Tree &root, Element e){
              TNode parent;
              
          bool isFound = search(root, NULL, parent, e);  //查找該結(jié)點(diǎn)
              if(isFound){  //已經(jīng)存在
                  printf("該結(jié)點(diǎn)已經(jīng)存在,插入操作失敗!");
                  
          return false;
              }
              TNode node 
          = (TNode)malloc(sizeof(Node));
              node
          ->data = e;
              node
          ->lchild = node->rchild = NULL;
              
          if(!parent){ //空樹
                  root = node;
              }
          else{
                  
          if(parent->data > e){
                      parent
          ->lchild = node;
                  }
          else{
                      parent
          ->rchild = node;
                  }
              }
              
          return true;
          }

          //先序遍歷
          void preorderTraversal(Tree root){
              
          if(root){
                  printf(format, root
          ->data);
                  preorderTraversal(root
          ->lchild);
                  preorderTraversal(root
          ->rchild);
              }
          }

          //中序遍歷二叉樹
          void inorderTraversal(Tree root){
              
          if(root){
                  inorderTraversal(root
          ->lchild);
                  printf(format, root
          ->data);
                  inorderTraversal(root
          ->rchild);
              }
          }

          //后序遍歷二叉樹
          void postorderTraversal(Tree root){
              
          if(root){
                  postorderTraversal(root
          ->lchild);
                  postorderTraversal(root
          ->rchild);
                  printf(format, root
          ->data);
              }
          }
            

           

            
          /**
           * <!--
           * File   : BinarySortTree.cpp
           * Author : fancy
           * Email  : fancydeepin@yeah.net
           * Date   : 2013-02-04
           * --!>
           
          */
          #include 
          "binarysorttree.h"

          int main() {

              
          //上圖所示的二叉樹先序遍歷序列,其中用'#'表示結(jié)點(diǎn)無左子樹或無右子樹
              Element data[27= {'M''J''E''C''#''#''G''F''#''#''I''H',
                                  
          '#','#''#''L''#''#''R''P''#''#''S''#''T''#''#'};
              Tree tree;
              treeNodeConstructor(tree, data);
              printf(
          "先序遍歷結(jié)果: ");
              preorderTraversal(tree);
              printf(
          "\n");
              
          //TEST 搜索
              TNode node = search(tree, 'F');
              
          if(node){
                  printf(
          "Found it : %c\n", node->data);
              }
          else{
                  printf(
          "NOT FOUND\n");
              }
              
          //TEST 插入結(jié)點(diǎn)
              insertNode(tree, 'K');
              printf(
          "插入K結(jié)點(diǎn)后,先序遍歷結(jié)果: ");
              preorderTraversal(tree);
              printf(
          "\n");
              
          //TEST 刪除無左右子樹的結(jié)點(diǎn)
              deleteNode(tree, 'P');
              printf(
          "刪除P結(jié)點(diǎn)后,先序遍歷結(jié)果: ");
              preorderTraversal(tree);
              printf(
          "\n");
              
          //TEST 刪除無左子樹的結(jié)點(diǎn)
              deleteNode(tree, 'S');
              printf(
          "刪除S結(jié)點(diǎn)后,先序遍歷結(jié)果: ");
              preorderTraversal(tree);
              printf(
          "\n");
              
          //TEST 刪除無右子樹的結(jié)點(diǎn)
              deleteNode(tree, 'I');
              printf(
          "刪除I結(jié)點(diǎn)后,先序遍歷結(jié)果: ");
              preorderTraversal(tree);
              printf(
          "\n");
              
          //TEST 刪除有左右子樹的結(jié)點(diǎn)
              deleteNode(tree, 'J');
              printf(
          "刪除J結(jié)點(diǎn)后,先序遍歷結(jié)果: ");
              preorderTraversal(tree);
              printf(
          "\n");
              
          /**
               * 控制臺輸出結(jié)果:
               *
               * 先序遍歷結(jié)果: MJECGFIHLRPST
               * Found it : F
               * 插入K結(jié)點(diǎn)后,先序遍歷結(jié)果: MJECGFIHLKRPST
               * 刪除P結(jié)點(diǎn)后,先序遍歷結(jié)果: MJECGFIHLKRST
               * 刪除S結(jié)點(diǎn)后,先序遍歷結(jié)果: MJECGFIHLKRT
               * 刪除I結(jié)點(diǎn)后,先序遍歷結(jié)果: MJECGFHLKRT
               * 刪除J結(jié)點(diǎn)后,先序遍歷結(jié)果: MHECGFLKRT
              
          */
              
          return 0;
          }
            


           



            
          posted on 2013-02-04 10:21 fancydeepin 閱讀(1842) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           

          隨筆分類(8)

          隨筆檔案(104)

          最新隨筆

          搜索

          •  

          積分與排名

          • 積分 - 1461491
          • 排名 - 15

          最新評論

          閱讀排行榜

          主站蜘蛛池模板: 望都县| 胶州市| 平顶山市| 师宗县| 潜江市| 锦州市| 泽库县| 盐池县| 岑溪市| 乐山市| 南部县| 七台河市| 呼玛县| 霍城县| 宜君县| 江山市| 昆山市| 蓬安县| 海兴县| 南阳市| 宜君县| 呼图壁县| 嘉兴市| 香港 | 东乌珠穆沁旗| 电白县| 易门县| 广昌县| 肥乡县| 丽水市| 广元市| 贺州市| 淳化县| 屯昌县| 雷山县| 高青县| 杭锦后旗| 台湾省| 安化县| 垣曲县| 安岳县|