演算法導論 第12章 二叉尋找樹

來源:互聯網
上載者:User
一、概念1.定義與性質(1)設x為二叉尋找樹中的一個結點,若y是x左子樹中的一個結點,則key[y] <= key[x];若y是x右子樹中的一個結點,則key[x]<=key[y](2)二叉尋找樹上執行的基本操作的時間與樹的高度成正比。2.結構(1)結點結構:關鍵字key衛星資料data分別指向父、左右孩子的指標p, left, right3.在二叉尋找樹上的操作尋找一個關鍵字:SEARCH(x, k)求最小關鍵字:MINIMUM(x)求最大關鍵字:MAXIMUM(x)求前驅:PREDECESSOR(x)求後繼:SUCCESSOR(x)插入一個結點:INSERT(T, z)刪除一個結點:DELETE(z)4.二叉尋找樹的應用

1.遍曆:中序遍曆、先序遍曆、後序遍曆

2.尋找:尋找包含某個關鍵字的結點,尋找關鍵字最大或最小的結點、尋找某個結點的前驅或後繼

 

二、代碼
#include <iostream>#include <string>using namespace std;struct BST_Node{public:int key;//關鍵字int data;//衛星資料BST_Node *left;//左孩子BST_Node *right;//右孩子BST_Node *p;//父結點BST_Node(int x):key(x),data(x),left(NULL),right(NULL),p(NULL){}};//二叉尋找樹的結構class BST_Tree{public:BST_Node *root;BST_Tree():root(NULL){}public://12.1 二叉尋找樹void Inorder_Tree_Walk(BST_Node *x);//12.2 查詢二叉尋找樹BST_Node *Tree_Search(BST_Node *x, int k);BST_Node *Iterative_Tree_Search(BST_Node *x, int k);BST_Node *Iterative_Tree_Minimum(BST_Node *x);BST_Node *Iterative_Tree_Maximum(BST_Node *x);BST_Node *Tree_Successor(BST_Node *x);//12.3 插入和刪除void Iterative_Tree_Insert(BST_Node *z);BST_Node *Tree_Delete(BST_Node *z);};/*************12.1 二叉尋找樹****************************************************************///遞迴的中序遍曆void BST_Tree::Inorder_Tree_Walk(BST_Node *x){if(x != NULL){//中序遍曆當前結點的左子樹Inorder_Tree_Walk(x->left);//訪問當前結點cout<<x->key<<endl;//中序遍曆當前結點的右子樹Inorder_Tree_Walk(x->right);}}/********12.2 查詢二叉尋找樹****************************************************************///遞迴地查詢二叉尋找樹BST_Node *BST_Tree::Tree_Search(BST_Node *x, int k){//找到葉子結點了還沒找到,或當前結點是所尋找的結點if(x == NULL || k == x->key)return x;//所尋找的結點位於當前結點的左子樹if(k < x->key)return Tree_Search(x->left, k);//所尋找的結點位於當前結點的左子樹elsereturn Tree_Search(x->right, k);}//非遞迴的查詢二叉尋找樹BST_Node *BST_Tree::Iterative_Tree_Search(BST_Node *x, int k){//不是葉子結點且不是所尋找的結點while(x != NULL && k != x->key){//所尋找的結點位於當前結點的左子樹if(k < x->key)x = x->left;//所尋找的結點位於當前結點的右子樹elsex = x->right;}return x;}//非遞迴找最小值BST_Node *BST_Tree::Iterative_Tree_Minimum(BST_Node *x){//只要有比當前結點小的結點while(x->left != NULL)x = x->left;return x;}//非遞迴找最大值BST_Node *Iterative_Tree_Maximum(BST_Node *x){//只要有比當前結點小的結點while(x->right != NULL)x = x->right;return x;}//尋找中序遍曆下x結點的後繼,後繼是大於key[x]的最小的結點BST_Node *BST_Tree::Tree_Successor(BST_Node *x){//如果有右孩子if(x->right != NULL)//右子樹中的最小值return Iterative_Tree_Minimum(x->right);//如果x的右子樹為空白且x有後繼y,那麼y是x的最低祖先結點,且y的左兒子也是BST_Node *y = x->p;while(y != NULL && x == y->right){x = y;y = y->p;}return y;}/*********12.3插入和刪除**********************************************************///二叉尋找樹的插入,非遞迴void BST_Tree::Iterative_Tree_Insert(BST_Node *z){//找到要插入的位置BST_Node *x = root, *y = NULL;//若x為空白,x是要插入的位置,x的父是z->pwhile(x != NULL){y = x;if(z->key == x->key){cout<<"error:exist"<<endl;return;}if(z->key < x->key)x = x->left;elsex = x->right;}//修改指標,注意樹為空白的情況z->p = y;if(y == NULL)root = z;else if(z->key < y->key)y->left = z;else y->right = z;}//二叉尋找樹的刪除,實際刪除的不一定是z,可能是z的後繼//然後把z的值改為實際刪除結點的值BST_Node *BST_Tree::Tree_Delete(BST_Node *z){BST_Node *x, *y;//若z最多隻有一個孩子,實際刪除的結點是zif(z->left == NULL || z->right == NULL)y = z;//若z有兩個孩子,實際刪除的結點是z的後繼elsey = Tree_Successor(z);//用x表示"實際要刪除的結點"的孩子(最多一個孩子)if(y->left != NULL)x = y->left;elsex = y->right;//修改指標,以刪去結點if(x != NULL)//若"實際要刪除的結點"沒有孩子x->p = y->p;if(y->p == NULL)//若"實際要刪除的結點"是根結點root = x;else if(y == y->p->left)y->p->left = x;else y->p->right = x;//"若初階要刪除的結點"不是"待刪除的結點",則內容替代if(y != z){z->key = y->key;z->data = y->data;}return y;}
三、練習12.1 二叉尋找樹

12.1-2

二叉尋找樹:左子樹關鍵字<根結點關鍵字<右子樹關鍵字

堆:左子樹關鍵字<根結點關鍵字 && 右子樹關鍵字<根結點關鍵字

不能,因為一個結點的的左子樹與右子樹的關鍵字大小沒有關係

12.1-3

用棧實現:見演算法導論-10.4-有根樹的表示中的10.4-3

不用棧實現:見演算法導論-10.4-5

12.1-4

//遞迴的先序遍曆  void BST_Tree::Preorder_Tree_Walk(BST_Node *x)  {      //x不是葉子結點      if(x != NULL)      {          //訪問當前結點          cout<<x->key<<' ';          //先序遍曆當前結點的左子樹          Preorder_Tree_Walk(x->left);          //先序遍曆當前結點的右子樹          Preorder_Tree_Walk(x->right);      }  }//遞迴的後序遍曆  void BST_Tree::Postorder_Tree_Walk(BST_Node *x)  {      //x不是葉子結點      if(x != NULL)      {          //後序遍曆當前結點的左子樹          Postorder_Tree_Walk(x->left);          //後序遍曆當前結點的右子樹          Postorder_Tree_Walk(x->right);          //訪問當前結點          cout<<x->data<<' ';      }  }

12.2 查詢二叉尋找樹
12.2-1c12.2-2//遞迴地尋找最小值  BST_Node *BST_Tree::Tree_Minimum(BST_Node *x)  {      if(x->left != NULL)          return Tree_Minimum(x->left);      else return x;  }  //遞迴的尋找最大值  BST_Node *BST_Tree::Tree_Maximum(BST_Node *x)  {      if(x->right != NULL)          return Tree_Maximum(x->right);      else return x;  } 12.2-3//尋找中序遍曆下x的前驅,即小於x的最大值  BST_Node *BST_Tree::Tree_Predecessor(BST_Node *x)  {      //如果x的左子樹非空      if(x->left != NULL)          //x的前驅是x的左子樹的最大值          return Tree_Maximum(x->left);      //如果x的左子樹為空白且x有前驅y,那麼y是x的最低祖先結點,且y的右兒子也是      BST_Node *y = x->p;      while(y != NULL && x == y->left)      {          x = y;          y = y->p;      }      return y;  }  12.2-4(1)4->left = 2 4->right =NIL2->left = 1 2->right = 3搜尋路徑4-2-1(2)1->right = 3 1->left = NUL3->left = 2 3->right = 4搜尋路徑1-3-4
12.3 插入和刪除

12.3-1

//遞迴的二叉尋找樹的插入操作,分三種情況  void BST_Tree::Tree_Insert(BST_Node *x, BST_Node *z)  {      //已經存在      if(z->key == x->key)      {          cout<<"error:exist"<<endl;          return;      }      //插入到x的左子樹中      else if(z->key < x->key)      {          //x沒有左子樹          if(x->left == NULL)          {              //修改指標,插入操作              x->left = z;              z->p = x;              return;          }          //x有左子樹          else              //對x的左子樹執行插入操作              Tree_Insert(x->left, z);      }      //插入到x的右子樹中,與上面類似      else if(z->key > x->key)      {          if(x->right == NULL)          {              x->right = z;              z->p = x;          }          else              Tree_Insert(x->right, z);      }  } 

12.3-3

最壞是n^2

最好是nlgn

12.3-4

求y的前驅z分為兩種情況,以下分別討論:

(1)y有左孩子,則z是left[y]中最右邊的結點,z沒有右孩子,因此刪除z時直接刪除修改指標即可,沒有問題

(2)y沒有左孩子,則z是y的祖先,y是z右子樹是最左邊的點,又分為兩種情況:

(2.1)若z沒有左孩子,則直接刪除z並修改指標,沒有問題。

(2.2)若z有左孩子,則不直接刪除z,而是用z代替y存在並刪除y。這裡會有問題,另一個資料結構中的儲存了指向y的指標,但是y的內容轉移到另一個結點上了,指向y的指標指向了一個被釋放的空間。

解決方案:使TREE-DELETE返回刪除後的y的指標,這個值可能會變,可能不變。讓另一個資料結構的y指標指向TREE-DELETE的傳回值。

12.3-5

不或交換,反例

12.3-6

當待刪除結點有兩個子樹時,不刪除待刪除結點,而是刪除它的前驅或後繼,用隨機數rand()%2來確定刪除的前驅還是後繼

代碼見文:二

 

四、思考題12-1 具有相同關鍵字元素的二叉樹

見演算法導論-12-1-具有相同關鍵字元素的二叉尋找樹

 

12-2 基數樹

見演算法導論-12-2-基數樹

 

12-3 隨機構造的二叉尋找樹中的平均結點深度

f)待解決

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.