二叉樹遍歷

遍歷概念:
  所謂遍歷(Traversal)是指沿着某條搜索路線,依次對樹中每個結點均做一次且僅做一次訪問。訪問結點所做的操作依賴於具體的應用問 題。
  遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。
  遍歷方案:
  1.遍歷方案
  從二叉樹的遞歸定義可知,一棵非空的二叉樹由根結點及左、右子樹這三個基本部分組成。因此,在任一給定結點上,可以按某種次序執行三個操作:
  (1)訪問結點本身(N),
  (2)遍歷該結點的左子樹(L),
  (3)遍歷該結點的右子樹(R)。
  以上三種操作有六種執行次序:
  NLR、LNR、LRN、NRL、RNL、RLN。
  注意:
  前三種次序與後三種次序對稱,故只討論先左後右的前三種次序。
  2.三種遍歷的命名
  根據訪問結點操作發生位置命名:
  ① NLR:前序遍歷(PreorderTraversal亦稱(先序遍歷))
  ——訪問結點的操作發生在遍歷其左右子樹之前。
  ② LNR:中序遍歷(InorderTraversal)
  ——訪問結點的操作發生在遍歷其左右子樹之中(間)。
  ③ LRN:後序遍歷(PostorderTraversal)
  ——訪問結點的操作發生在遍歷其左右子樹之後。
  注意:
  由於被訪問的結點必是某子樹的根,所以N(Node)、L(Left subtlee)和R(Right subtree)又可解釋爲根、根的左子樹和根的右子樹。NLR、LNR和LRN分別又稱爲先根遍歷、中根遍歷和後根遍歷。
  遍歷算法
  1.中序遍歷的遞歸算法定義:
  若二叉樹非空,則依次執行如下操作:
  (1)遍歷左子樹;
  (2)訪問根結點;
  (3)遍歷右子樹。
  2.先序遍歷的遞歸算法定義:
  若二叉樹非空,則依次執行如下操作:
  (1) 訪問根結點;
  (2) 遍歷左子樹;
  (3) 遍歷右子樹。
  3.後序遍歷得遞歸算法定義:
  若二叉樹非空,則依次執行如下操作:
  (1)遍歷左子樹;
  (2)遍歷右子樹;
  (3)訪問根結點。
  4.中序遍歷的算法實現
  用二叉鏈表做爲存儲結構,中序遍歷算法可描述爲:
  void InOrder(BinTree T)
  { //算法裏①~⑥是爲了說明執行過程加入的標號
  ① if(T) { // 如果二叉樹非空
  ② InOrder(T->lchild);
  ③ printf("%c",T->data); // 訪問結點
  ④ InOrder(T->rchild);
  ⑤ }
  ⑥ } // InOrder
  遍歷序列
  1.遍歷二叉樹的執行蹤跡
  三種遞歸遍歷算法的搜索路線相同(如下圖虛線所示)。
  具體線路爲:
  從根結點出發,逆時針沿着二叉樹外緣移動,對每個結點均途徑三次,最後回到根結點。
  2.遍歷序列
  (1) 中序序列
  中序遍歷二叉樹時,對結點的訪問次序爲中序序列
  【例】中序遍歷上圖所示的二叉樹時,得到的中序序列爲:
  D B A E C F
  (2) 先序序列
  先序遍歷二叉樹時,對結點的訪問次序爲先序序列
  【例】先序遍歷上圖所示的二叉樹時,得到的先序序列爲:
  A B D C E F
  (3) 後序序列
  後序遍歷二叉樹時,對結點的訪問次序爲後序序列
  【例】後序遍歷上圖所示的二叉樹時,得到的後序序列爲:
  D B E F C A
  注意:
  (1)在搜索路線中,若訪問結點均是第一次經過結點時進行的,則是前序遍歷;若訪問結點均是在第二次(或第三次)經過結點時進行的,則是中序遍歷(或後序遍歷)。只要將搜索路線上所有在第一次、第二次和第三次經過的結點分別列表,即可分別得到該二叉樹的前序序列、中序序列和後序序列。
  (2)上述三種序列都是線性序列,有且僅有一個開始結點和一個終端結點,其餘結點都有且僅有一個前趨結點和一個後繼結點。爲了區別於樹形結構中前趨(即雙親)結點和後繼(即孩子)結點的概念,對上述三種線性序列,要在某結點的前趨和後繼之前冠以其遍歷次序名稱。
  【例】上圖所示的二叉樹中結點C,其前序前趨結點是D,前序後繼結點是E;中序前趨結點是E,中序後繼結點是F;後序前趨結點是F,後序後繼結點是A。但是就該樹的邏輯結構而言,C的前趨結點是A,後繼結點是E和F。
  二叉鏈表的構造
  1. 基本思想
  基於先序遍歷的構造,即以二叉樹的先序序列爲輸入構造。
  注意:
  先序序列中必須加入虛結點以示空指針的位置。
  【例】
  建立上圖所示二叉樹,其輸入的先序序列是:ABD∮∮∮CE∮∮F∮∮。
  2. 構造算法
  假設虛結點輸入時以空格字符表示,相應的構造算法爲:
  void CreateBinTree (BinTree *T)
  { //構造二叉鏈表。T是指向根指針的指針,故修改*T就修改了實參(根指針)本身
  char ch;
  if((ch=getchar())=='') *T=NULL; //讀人空格,將相應指針置空
  else{ //讀人非空格
  *T=(BinTNode *)malloc(sizeof(BinTNode)); //生成結點
  (*T)->data=ch;
  CreateBinTree(&(*T)->lchild); //構造左子樹
  CreateBinTree(&(*T)->rchild); //構造右子樹
  }
  }
  注意:
  調用該算法時,應將待建立的二叉鏈表的根指針的地址作爲實參。
  【例】
  設root是一根指針(即它的類型是BinTree),則調用CreateBinTree(&root)後root就指向了已構造好的二叉鏈表的根結點。
  二叉樹建立過程見http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/erchashujianli.htm
  下面是關於二叉樹的遍歷、查找、刪除、更新數據的代碼(遞歸算法):
  
  #include <iostream>
  using namespace std;
  typedef int T;
  class bst{
  struct Node{
  T data;
  Node* L;
  Node* R;
  Node(const T& d, Node* lp=NULL, Node* rp=NULL):data(d),L(lp),R(rp){}
  };
  Node* root;
  int num;
  public:
  bst():root(NULL),num(0){}
  void clear(Node* t){
  if(t==NULL) return;
  clear(t->L);
  clear(t->R);
  delete t;
  }
  ~bst(){clear(root);}
  void clear(){
  clear(root);
  num = 0;
  root = NULL;
  }
  bool empty(){return root==NULL;}
  int size(){return num;}
  T getRoot(){
  if(empty()) throw "empty tree";
  return root->data;
  }
  void travel(Node* tree){
  if(tree==NULL) return;
  travel(tree->L);
  cout << tree->data << ' ';
  travel(tree->R);
  }
  void travel(){
  travel(root);
  cout << endl;
  }
  int height(Node* tree){
  if(tree==NULL) return 0;
  int lh = height(tree->L);
  int rh = height(tree->R);
  return 1+(lh>rh?lh:rh);
  }
  int height(){
  return height(root);
  }
  void insert(Node*& tree, const T& d){
  if(tree==NULL)
  tree = new Node(d);
  else if(ddata)
  insert(tree->L, d);
  else
  insert(tree->R, d);
  }
  void insert(const T& d){
  insert(root, d);
  num++;
  }
  Node*& find(Node*& tree, const T& d){
  if(tree==NULL) return tree;
  if(tree->data==d) return tree;
  if(ddata)
  return find(tree->L, d);
  else
  return find(tree->R, d);
  }
  bool find(const T& d){
  return find(root, d)!=NULL;
  }
  bool erase(const T& d){
  Node*& pt = find(root, d);
  if(pt==NULL) return false;
  combine(pt->L, pt->R);
  Node* p = pt;
  pt = pt->R;
  delete p;
  num--;
  return true;
  }
  void combine(Node* lc, Node*& rc){
  if(lc==NULL) return;
  if(rc==NULL) rc = lc;
  else combine(lc, rc->L);
  }
  bool update(const T& od, const T& nd){
  Node* p = find(root, od);
  if(p==NULL) return false;
  erase(od);
  insert(nd);
  return true;
  }
  };
  int main()
  {
  bst b;
  cout << "input some integers:";
  for(;;){
  int n;
  cin >> n;
  b.insert(n);
  if(cin.peek()=='\n') break;
  }
  b.travel();
  for(;;){
  cout << "input data pair:";
  int od, nd;
  cin >> od >> nd;
  if(od==-1&&nd==-1) break;
  b.update(od, nd);
  b.travel();
  }
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章