二叉查找树通俗说就是左孩子比父亲小,右孩子比父亲大。构造这么一个树,树嘛,递归即可。

  例如一棵树后序遍历是这样(下图的树):2 9 8 16 15 10 25 38 45 42 30 20。最后的20肯定是树根,这里要抓住一个规律:20是树根,那么2 9 8 16 15 10都是左子树,25 38 42 45 30在右子树,因为左边都小于根、右边都大于根嘛。然后递归即可。

  下面是树的样子和代码和src.txt(后序遍历的结果)以及运行结果:

 1 #include <iostream>
 2 #include <vector>
 3 #include <fstream>
 4 
 5 using std::cin;
 6 using std::cout;
 7 using std::endl;
 8 using std::vector;
 9 
10 #define MY_DEBUG
11 
12 struct Node
13 {
14     int data;
15     Node* pLC;
16     Node* pRC;
17 };
18 
19 Node* creatBSTree(vector<int>& arr)
20 {
21     //数组里面没有元素
22     if (!arr.size())
23         return nullptr;
24 
25     Node* pNode = new Node;
26     int thisData = arr.back();
27     pNode->data = thisData;
28 
29     //只有一个元素就不要折腾了,它就是叶子节点,它没有左右孩子
30     if (1 == arr.size())
31     {
32         pNode->pLC = pNode->pRC = nullptr;
33         return pNode;
34     }
35 
36     //下面找出左半边
37     vector<int> arrLeft;
38     for (int i = 0; i < arr.size() - 1; i++)
39     {
40         if (arr[i] < thisData)
41             arrLeft.push_back(arr[i]);
42         else
43             break;
44     }
45 
46     //下面找出右半边
47     vector<int> arrRight;
48     for (int i = arrLeft.size(); i < arr.size() - 1; i++)
49         arrRight.push_back(arr[i]);
50 
51 #ifdef MY_DEBUG
52     for (int i = 0; i < arrLeft.size(); i++)
53         cout << arrLeft[i] << " ";
54     cout << endl;
55 
56     for (int i = 0; i < arrRight.size(); i++)
57         cout << arrRight[i] << " ";
58     cout << endl << endl;
59 #endif
60 
61     //递归处理左右孩子。arrLeft和arrRight可能为空,不要紧,在函数的开头处理了
62     pNode->pLC = creatBSTree(arrLeft);
63     pNode->pRC = creatBSTree(arrRight);
64 
65     return pNode;
66 }
67 
68 
69 //中序遍历
70 void show(Node* pNode)
71 {
72     if (!pNode)
73         return;
74 
75     show(pNode->pLC);
76     cout << pNode->data << "  ";
77     show(pNode->pRC);
78 }
79 
80 int main(void)
81 {
82     vector<int> arr;
83     std::ifstream fin("src.txt");
84 
85     int temp;
86     while (fin >> temp)
87         arr.push_back(temp);
88 
89     Node* pHead = creatBSTree(arr);
90     show(pHead);
91     cout << endl;
92     cin.get();
93 }
View Code
2 9 8 16 15 10 25 38 45 42 30 20

  由其他的遍历方式得到树的道理类似。




 

题目:

  输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。

分析:

  这不是很简单了嘛,由最后的根把输入分成三份,第一份是左孩子,第二份是右孩子,最后是树根。7、4、6、5就不能构成了,因为5是根,那么7,4,6都是右子树里面的,但是里面有小于5的4,所以不行。递归即可。




 

题目:

  输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。

  例如如果树如上图,那么得到的链表是 2=8=9=……=42=45。

分析:

  树嘛,递归就是啦。

  如上树,先递归处理左子树(根为10的树),处理完左子树就成了一个链表了,并要能够返回左子树的最大节点16;然后递归处理右子树(根为30的树),处理完右子树也成了一个有序链表,并返回右子树的最小节点25,然后把16、20、25串起来,不就是链表了嘛?

  这里要注意一点:在处理根为20的树时,这是不是要递归处理根为10的左子树嘛,那么这个左子树怎么知道它要返回16节点呢?同样对于20的右子树,它怎么知道返回25以和20串起来呢?所以在处理子树的时候,要传给它一个标志,表明它是父亲的左子树还是右子树。我在这里纠结好久……

代码:

  1 #include <iostream>
  2 #include <set>
  3 #include <fstream>
  4 #include <queue>
  5 
  6 using std::cin;
  7 using std::cout;
  8 using std::endl;
  9 using std::set;
 10 using std::vector;
 11 
 12 struct Node
 13 {
 14     int data;
 15     Node* pLC;
 16     Node* pRC;
 17 };
 18 
 19 Node* creatBSTree(vector<int>& arr)
 20 {
 21     //数组里面没有元素
 22     if (!arr.size())
 23         return nullptr;
 24 
 25     Node* pNode = new Node;
 26     int thisData = arr.back();
 27     pNode->data = thisData;
 28 
 29     //只有一个元素就不要折腾了,它就是叶子节点,它没有左右孩子
 30     if (1 == arr.size())
 31     {
 32         pNode->pLC = pNode->pRC = nullptr;
 33         return pNode;
 34     }
 35 
 36     //下面找出左半边
 37     vector<int> arrLeft;
 38     for (int i = 0; i < arr.size() - 1; i++)
 39     {
 40         if (arr[i] < thisData)
 41             arrLeft.push_back(arr[i]);
 42         else
 43             break;
 44     }
 45 
 46     //下面找出右半边
 47     vector<int> arrRight;
 48     for (int i = arrLeft.size(); i < arr.size() - 1; i++)
 49         arrRight.push_back(arr[i]);
 50 
 51 #ifdef MY_DEBUG
 52     for (int i = 0; i < arrLeft.size(); i++)
 53         cout << arrLeft[i] << " ";
 54     cout << endl;
 55 
 56     for (int i = 0; i < arrRight.size(); i++)
 57         cout << arrRight[i] << " ";
 58     cout << endl << endl;
 59 #endif
 60 
 61     //递归处理左右孩子。arrLeft和arrRight可能为空,不要紧,在函数的开头处理了
 62     pNode->pLC = creatBSTree(arrLeft);
 63     pNode->pRC = creatBSTree(arrRight);
 64 
 65     return pNode;
 66 }
 67 
 68 //中序遍历
 69 void show(Node* pNode)
 70 {
 71     if (!pNode)
 72         return;
 73 
 74     show(pNode->pLC);
 75     cout << pNode->data << " ";
 76     show(pNode->pRC);
 77 }
 78 
 79 //这个函数多传了一个参数 asLeft,表明树根是树根的左子树还是右子树
 80 //因为如果是左子树的话,那么要返回左子树最大节点,右子树要返回最小节点
 81 //不要这个标志的话 pNode 不知道指向的树到底是父亲的左子树还是右子树
 82 Node* letStraight(Node* pNode, bool asLeft)
 83 {
 84     //如果是空树或者只是一个叶子节点,返回自身
 85     if (!pNode || (!pNode->pLC && !pNode->pRC))
 86         return pNode;
 87 
 88     //递归处理左右子树
 89     Node* pLMax = nullptr;
 90     if (pNode->pLC)
 91         pLMax = letStraight(pNode->pLC, true);
 92 
 93     Node* pRMin = nullptr;
 94     if (pNode->pRC)
 95         pRMin = letStraight(pNode->pRC, false);
 96 
 97     //连接左子树、右子树、树根
 98     if (pLMax)
 99     {
100         pNode->pLC = pLMax;
101         pLMax->pRC = pNode;
102     }
103     if (pRMin)
104     {
105         pNode->pRC = pRMin;
106         pRMin->pLC = pNode;
107     }
108 
109     //返回值处理,注意 asLeft 表明这棵树是它父亲的左子树还是右子树,所以它要重新找到合适的返回节点
110     // pNode 的左孩子最大或右孩子最小并不是它要返回的值,它要返回的还是要看这整棵树,而不是单单看左右孩子
111     Node* pRetutnNode = pNode;
112     if (asLeft)
113     {
114         while (pRetutnNode->pRC)
115             pRetutnNode = pRetutnNode->pRC;
116     } 
117     else
118     {
119         while (pRetutnNode->pLC)
120             pRetutnNode = pRetutnNode->pLC;
121     }
122     return pRetutnNode;
123 }
124 
125 int main(void)
126 {
127     vector<int> arr;
128     std::ifstream fin("src.txt");
129 
130     int temp;
131     while (fin >> temp)
132         arr.push_back(temp);
133 
134     Node* pHead = creatBSTree(arr);
135     show(pHead);
136     cout << endl;
137 
138     //顺序链表化并返回第一个节点
139     pHead = letStraight(pHead, false);
140     while (pHead)
141     {
142         cout << pHead->data << " ";
143         pHead = pHead->pRC;
144     }
145     cout << endl;
146 
147     cin.get();
148 }
View Code

结果:

posted on 2014-08-27 12:10  简单的信仰  阅读(662)  评论(0编辑  收藏  举报