亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

一波C語言二元查找樹算法題目解答實例匯總

2020-01-26 14:40:45
字體:
來源:轉載
供稿:網友

按層次遍歷二元樹
問題描述:輸入一顆二元樹,從上往下按層打印樹的每個結點,同一層中按照從左往右的順序打印。 
例如輸入:

 8 / / 6 10/ / / /5 7 9 11

輸出

8 6 10 5 7 9 11

          定義二元樹(其實是二元搜索樹,但并不遍歷算法)的結點為:

struct BSTreeNode {  int value;  BSTreeNode *left;  BSTreeNode *right; }; 

      思路:利用隊列的先進先出,很容易實現。每次取出隊列的首元素,然后將其左右子女放入隊列中。直至隊列為空即可。按這種方式進出隊列,正好是按層遍歷二元樹。
      參考代碼:

//函數功能 : 按層次遍歷二元樹 //函數參數 : pRoot指向根結點 //返回值 : 無 void LevelReverse(BSTreeNode *pRoot) {  if(pRoot == NULL)   return;   queue<BSTreeNode *> nodeQueue;  nodeQueue.push(pRoot);  while(nodeQueue.size())  {   BSTreeNode * pNode = nodeQueue.front(); //取隊首元素   nodeQueue.pop(); //必須出隊列   if(pNode->left) //左子女    nodeQueue.push(pNode->left);   if(pNode->right) //右子女    nodeQueue.push(pNode->right);    cout<<pNode->value<<' ';  } } 

       擴展一:上文給出的代碼,所有結點都輸出在同一行。如果希望僅僅同層結點輸出在同一行,該如何修改代碼呢?
       思路:如果我們能知道每層的最后一個結點,那么就方便多了,輸出每層最后一個結點的同時,輸出一個換行符。因此,關鍵在于如何標記每層的結束??梢钥紤]在每層的最后一個點之后,插入一個空結點。比如隊列中先放入根結點,由于第0層只有一個結點,因此放入一個空結點。然后依次取出隊列中的結點,將其子女放入隊列中,如果遇到空結點,表明當前層的結點已遍歷完了,而隊列中放的恰恰是下一層的所有結點。如果當前隊列為空,表明下一層無結點,也就說是所有結點已遍歷好了。如果不為空,那么插入一個空結點,用于標記下一層的結束。
      參考代碼:

void LevelReverse(BSTreeNode *pRoot) {  if(pRoot == NULL)   return;  queue<BSTreeNode *> nodeQueue;  nodeQueue.push(pRoot);  nodeQueue.push(NULL); //放入空結點,作為層的結束符  while(nodeQueue.size())  {   BSTreeNode * pNode = nodeQueue.front(); //取隊首元素   nodeQueue.pop(); //必須出隊列   if(pNode)   {    if(pNode->left) //左子女     nodeQueue.push(pNode->left);    if(pNode->right) //右子女     nodeQueue.push(pNode->right);    cout<<pNode->value<<' ';   }   else if(nodeQueue.size()) //如果結點為空并且隊列也為空,那么所有結點都已訪問   {    nodeQueue.push(NULL);    cout<<endl;   }  } } 

       擴展二:之前討論的都是從上往下、從左往右遍歷二叉樹,那么如果希望自下往上、從左右往右遍歷二叉樹,該如何修改代碼呢?
       思路:比較簡單的方法,首先遍歷二叉樹,將所有結點保存在一個數組中,遍歷的同時記錄每一層在數組中的起止位置。然后根據起止位置,就可以自下往上的打印二叉樹的結點。

//每層的起止位置 struct Pos {  int begin;  int end;  Pos(int b, int e): begin(b),end(e) {} }; void LevelReverse(BSTreeNode *pRoot) {  if(pRoot == NULL)   return;   vector<BSTreeNode*> vec; //用以存放所有結點  vector<Pos> pos;   //用以記錄每層的起止位置  vec.push_back(pRoot);   int level = 0; //樹的層數  int cur = 0;  int last = 1;   while(cur < vec.size())  {   last = vec.size();   pos.push_back(Pos(cur, last)); //記錄當前層的起止位置    while(cur < last) //遍歷當前層的結點,將子女放入數組中   {    if(vec[cur]->left) //先是左然后是右。如果希望自由向左,交換一下順序即可     vec.push_back(vec[cur]->left);    if(vec[cur]->right)     vec.push_back(vec[cur]->right);    cur++;   }   level++; //層數加1  }   for(int i = level - 1; i >= 0; i--) //自下往上遍歷  {   for(int j = pos[i].begin; j < pos[i].end; j++)    cout<<vec[j]->value<<' ';   cout<<endl;  } } 

輸入一顆二元查找樹,將該樹轉換為它的鏡像
  問題描述:輸入一顆二元查找樹,將該樹轉換為它的鏡像,即在轉換后的二元查找樹中,左子樹的結點都大于右子樹的結點。用遞歸和循環兩種方法完成樹的鏡像轉換。 
        例如輸入:

 8 / / 6 10 // //5 7 9 11

輸出:

 8 / / 10 6 // //11 9 7 5

      定義二元查找樹的結點為:

struct BSTreeNode {  int value;  BSTreeNode *left;  BSTreeNode *right; }; 

      思路:題目要求用兩種方法,遞歸和循環,其實質是一樣的。
      解法一:用遞歸。假設當前結點為pNode,只需交換該結點的左右子女,然后分別遞歸求解左子樹和右子樹即可。代碼極為簡單。
      解法二:用循環,需要一個輔助棧完成,每次取棧頂元素交換左右子女,然后將左右子女分別壓入輔助棧,當棧中元素為空時,結束循環。其實不論是遞歸也好,循環也好,都是利用棧的特性完成。
      參考代碼:

//函數功能 : 輸入一顆二元查找樹,將該樹轉換為它的鏡像 //函數參數 : pRoot為根結點 //返回值 : 根結點 BSTreeNode * Mirror_Solution1(BSTreeNode * pRoot) {  if(pRoot != NULL)  {   BSTreeNode * pRight = pRoot->right;   BSTreeNode * pLeft = pRoot->left;   pRoot->left = Mirror_Solution1(pRight); //轉化右子樹   pRoot->right = Mirror_Solution1(pLeft); //轉化左子樹  }  return pRoot; } BSTreeNode * Mirror_Solution2(BSTreeNode * pRoot) {  if(pRoot != NULL)  {   stack<BSTreeNode *> stk; //輔助棧   stk.push(pRoot);   //壓入根結點   while(stk.size())   {    BSTreeNode *pNode = stk.top();    BSTreeNode *pLeft = pNode->left;    BSTreeNode* pRight = pNode->right;    stk.pop();     if(pLeft != NULL)     stk.push(pLeft);    if(pRight != NULL)     stk.push(pRight);    pNode->left = pRight; //交換左右子女    pNode->right = pLeft;   }  }  return pRoot; } 

判斷整數序列是不是二元查找樹的后序遍歷結果
問題描述:輸入一個整數數組,判斷該數組是不是某二元查找樹的后序遍歷的結果。如果是返回true,否則返回false。
例如輸入5、7、6、9、11、10、8,由于這一整數序列是如下樹的后序遍歷結果:

   8  / /  6 10 / / / / 5 7 9 11

因此返回true。如果輸入7、4、6、5,沒有哪棵樹的后序遍歷的結果是這個序列,因此返回false。
         思路:分析后序遍歷的特點,序列的最后一個數應該是根結點,剩余的節點分為兩個連續的子序列,前一子序列的值小于最后一個數,后一子序列的值大于最后一個數。然后遞歸求解這兩個子序列。
         如果是判斷是前序遍歷也很簡單,只不過根節點變為了第一個數,剩余的節點也是分為兩個連續的子序列。如果判斷是中序遍歷,更方便,只需掃描一遍,檢查序列是不是排好序的,如果沒有排好序,就不是中序遍歷的結果。


把二元查找樹轉變成排序的雙向鏈表
    問題描述:輸入一棵二元查找樹,將該二元查找樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只調整指針的指向。

 10 / / 6 14 / / / /4 8 12 16

 轉換成雙向鏈表

4=6=8=10=12=14=16

   思路:利用遞歸的思想求解,分別調整某結點的左右子樹,調整完后,將該結點的左指針指向左子樹的最大節點,右指針指向右子樹的最小節點。
   代碼如下:

BSTreeNode * Convert(BSTreeNode *node) {  if(node == NULL)   return NULL;  BSTreeNode *leftMax,*rightMin;  leftMax = node->left;   rightMin = node->right;  //找到左子樹的最大結點  while(leftMax != NULL && leftMax->right != NULL)   leftMax = leftMax->right;  //找到右子樹的最小結點  while(rightMin != NULL && rightMin->left != NULL)   rightMin = rightMin->left;  //遞歸求解  Convert(node->right);  Convert(node->left);  //將左右子樹同根結點連起來,只不過是以兄弟的關系  if(leftMax != NULL)   leftMax->right = node;  if(rightMin != NULL)   rightMin->left = node;  node->left = leftMax;  node->right = rightMin;  return node; } 

   測試當中,需要建立二叉搜索樹,下面給出建立及遍歷二叉樹的代碼。

struct BSTreeNode {  int value;  BSTreeNode *left;  BSTreeNode *right; }; BSTreeNode * Insert(BSTreeNode *p, int x) {  if(p == NULL)  {   p = new BSTreeNode;   p->value = x;   p->left = NULL;   p->right = NULL;  }  else  {   if(p->value > x)    p->left = Insert(p->left, x);   if(p->value < x)    p->right = Insert(p->right, x);  }  return p; } void Traverse(BSTreeNode *p) //中序遍歷 {  if(p == NULL)   return;  Traverse(p->left);  cout<<p->value<<' ';  Traverse(p->right); } 

在二元樹中找出和為某一值的所有路徑(樹)
   問題描述:輸入一個整數和一棵二元樹。從樹的根結點開始往下訪問一直到葉結點所經過的所有結點形成一條路徑。打印出和與輸入整數相等的所有路徑。
例如輸入整數22和如下二元樹

 10  / /  5 12  / / 4  7

則打印出兩條路徑:10, 12和10, 5, 7。
二元樹節點的數據結構定義為:

struct BinaryTreeNode{int data;BinaryTreeNode *pLeft;BinaryTreeNode *pRight;};

    思路:遞歸的思想。很多樹的題目都是用遞歸解決的,例如把二元查找樹轉變成排序的雙向鏈表(樹)。遞歸的終止條件為當前為空結點或當前結點的值大于剩余和。如果當前結點的值等于剩余和,并且是葉結點,那么打印路徑。否則,將剩余和減去當前結點的值,遞歸求解。至于路徑的記錄,可以利用棧的思想來實現。
       代碼:

void FindPath(BinaryTreeNode *pNode,int sum,vector<int> &path) {  //結點為空或值大于當前和  if(pNode == NULL || pNode->data > sum)   return;  path.push_back(pNode->data);  //判斷是不是葉結點  bool isLeaf = (pNode->pLeft == NULL && pNode->pRight == NULL)? true: false;  //找到一條路徑,打印  if(pNode->data == sum && isLeaf)  {   vector<int>::iterator iter = path.begin();   for(; iter != path.end(); iter++)    cout<<*iter<<' ';   cout<<endl;  }  else  {   //求剩余和   sum = sum - pNode->data;   //遞歸求解   FindPath(pNode->pLeft, sum, path);   FindPath(pNode->pRight, sum, path);  }  path.pop_back(); } 

判斷二叉樹是不是平衡的
問題描述:輸入一棵二叉樹的根結點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意結點的左右子樹的深度相差不超過1,那么它就是一棵平衡二叉樹。例如下圖中的二叉樹就是一棵平衡二叉樹:

2016315154803523.gif (199×180)

思路:對于樹的題目,第一反應就是用遞歸。對于以某個結點為根的樹,只需計算出它的左右子樹的深度,如果深度相差小于等于1,則遞歸判斷它的左右子樹是不是平衡樹;否則肯定不是平衡二叉樹。這個問題的關鍵是要計算樹的深度,如果是自頂向下,會有很多重復的計算。計算以1為根的樹的深度,會牽涉到以2為根、以3為根的子樹。計算以2為根的樹的深度,會牽涉到以4為根、以5為根的子樹。由于要遍歷每個結點,判斷以該結點為根的樹是不是平衡二叉樹。所以計算以1為根的樹的深度,與計算以2為根的樹的深度,會重復計算以4為根、以5為根的子樹的深度。

消除重復辦法,當時是能記錄下之前計算過的子樹的深度,下次使用就不用重新計算。這就需要自底向上的計算深度。慶幸的是遞歸解決樹的問題,就是自底向上的過程。因為我們在遞歸求解中,先要得出子樹的解,子樹的解最終會轉換為葉結點的解??梢岳煤笮虮闅v的方法,遍歷每個結點時,先判斷它的左右子樹是不是平衡二叉樹,同時記錄下左右子樹的深度,然后判斷該結點為根的樹是不是平衡二叉樹,至于該樹的深度計算很方便,取左右子樹中較大的深度+1就可以了。這里左右子樹的深度在遞歸求解中已經計算出來,不需要重復計算了。

參考代碼:

struct BinaryTreeNode {   int data;   BinaryTreeNode *pLeft;   BinaryTreeNode *pRight; }; //函數功能 : 判斷二叉樹是不是平衡的 //函數參數 : pRoot為根結點,pDepth為根結點的深度。 //返回值 :  是否平衡的 bool IsBalanced(BinaryTreeNode *pRoot, int *pDepth) {   if(pRoot == NULL)   {     *pDepth = 0;     return true;   }   int leftDepth, rightDepth; //左右子樹的深度   if(IsBalanced(pRoot->pLeft, &leftDepth)&&     IsBalanced(pRoot->pRight, &rightDepth))   {     int diff = leftDepth - rightDepth;     if(diff == 0 || diff == 1 || diff == -1) //相差為0或1或-1     {       *pDepth = 1 + (leftDepth > rightDepth ? leftDepth: rightDepth);        return true;     }     else       return false;   }   return false; } 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲成成品网站| 欧亚精品中文字幕| 亚洲午夜未删减在线观看| 亚洲va码欧洲m码| 久久久久免费视频| 欧美一区二区大胆人体摄影专业网站| 国产精品91视频| 精品爽片免费看久久| 欧美性xxxx极品高清hd直播| 92版电视剧仙鹤神针在线观看| 亚洲免费高清视频| 欧美裸体xxxx| 欧美精品在线免费播放| 在线电影欧美日韩一区二区私密| 中文字幕亚洲欧美日韩2019| 亚洲欧美日韩第一区| 欧美性生交xxxxxdddd| 北条麻妃99精品青青久久| 亚洲欧美另类在线观看| 国产主播欧美精品| 国产精品九九久久久久久久| 欧美综合在线观看| 欧美性生交大片免网| 国产精品久久久久国产a级| 亚洲精品短视频| 久久国产精品亚洲| 国产精品一二三视频| 国外成人在线视频| 秋霞成人午夜鲁丝一区二区三区| 日韩精品中文在线观看| 国产精品91久久久| 国产精品视频一区国模私拍| 欧美成人三级视频网站| 久久久成人精品视频| 91精品久久久久久久久久另类| 欧美性色19p| 久久久视频精品| 国产自产女人91一区在线观看| 国产视频在线观看一区二区| 中文字幕日韩欧美精品在线观看| 日韩欧美国产激情| 成人激情春色网| 国产精品久久99久久| 久久精品在线视频| 亚洲黄色片网站| 成人羞羞国产免费| 欧美午夜激情小视频| 91精品国产乱码久久久久久蜜臀| 成人精品一区二区三区电影黑人| 久久精品视频在线观看| 亚洲美女在线观看| 色综合久久88| 91在线观看欧美日韩| 欧美自拍视频在线观看| 亚洲国产精品99| 夜夜躁日日躁狠狠久久88av| 91精品久久久久久久久久入口| 成人黄色短视频在线观看| 欧美国产第一页| 国产一区二区视频在线观看| 精品无人区乱码1区2区3区在线| 国产精品久久久久久久7电影| 成人性生交大片免费观看嘿嘿视频| 亚洲国产成人精品电影| 亚洲韩国欧洲国产日产av| 亚洲qvod图片区电影| 黑人与娇小精品av专区| 欧美国产欧美亚洲国产日韩mv天天看完整| 欧美国产日韩视频| 亚洲激情在线观看| 日韩欧美亚洲一二三区| 午夜精品久久久久久久男人的天堂| 亚洲精品日韩久久久| 亚洲97在线观看| 精品亚洲一区二区三区| 夜夜嗨av一区二区三区免费区| 精品亚洲va在线va天堂资源站| 精品人伦一区二区三区蜜桃网站| 欧美性高潮在线| 自拍偷拍亚洲在线| 色综合天天综合网国产成人网| 国外日韩电影在线观看| 亚洲а∨天堂久久精品喷水| 亚洲天堂av在线免费观看| 国产精品美女久久久久av超清| 欧美一级大片在线观看| 国产精品一区二区久久久| 操91在线视频| 中文字幕九色91在线| 欧美日韩国产黄| 日韩在线免费视频观看| 国产啪精品视频| 丝袜一区二区三区| 国产精品678| 久国内精品在线| 日韩国产激情在线| 性欧美视频videos6一9| 91chinesevideo永久地址| 日韩欧美在线看| 2019亚洲男人天堂| 精品久久久久久久久久久久| 国产97色在线|日韩| 久久亚洲国产成人| 姬川优奈aav一区二区| 日韩免费电影在线观看| 国产在线精品成人一区二区三区| 欧美午夜xxx| 日韩免费精品视频| 日韩女优人人人人射在线视频| 欧美电影免费观看网站| 亚洲欧洲免费视频| 国产精品成人免费视频| 亚洲欧洲在线观看| 欧美—级a级欧美特级ar全黄| 亚洲福利视频二区| 国产在线观看91精品一区| 国产亚洲精品成人av久久ww| 国产亚洲精品高潮| 欧美激情亚洲另类| 九九精品在线播放| 国产成人激情视频| 久久久久亚洲精品成人网小说| 日本久久久久久| 日韩成人在线视频| 欧美性视频网站| 日韩视频亚洲视频| 欧美在线视频一区| 欧美成人精品一区| 国产欧美精品va在线观看| 日韩亚洲成人av在线| 午夜精品久久久久久久99热浪潮| 日韩一区二区三区在线播放| 国产精品第七影院| 91欧美视频网站| 日韩中文理论片| 午夜免费在线观看精品视频| 国产精品免费小视频| 欧美激情第99页| 国产精品一区二区三区久久久| 午夜精品久久久久久久久久久久| 亚洲欧美国产一区二区三区| 亚洲久久久久久久久久久| 91精品免费看| 久久99精品国产99久久6尤物| 日韩av影片在线观看| 欧美色欧美亚洲高清在线视频| 亚洲国产福利在线| 欧美激情videoshd| 久精品免费视频| 亚洲永久在线观看| 久久久久久国产精品美女| 亚洲国产欧美一区二区三区同亚洲| 久久精品视频亚洲| 成人免费淫片视频软件| 91精品在线一区| 久久伊人免费视频| 日韩成人在线电影网| 欧美成人国产va精品日本一级| 日韩精品999| 久久精品亚洲94久久精品| 中文字幕亚洲无线码在线一区| 久久伊人精品天天| 97视频人免费观看| 精品视频偷偷看在线观看|