二叉搜索树

二叉搜索树的建立是通过递归方式来建立的,和普通的二叉树的区别是加上了约束, 它的左子树的所有元素都要比根节点要小, 而右子树的所有元素都要根节点要大,左右子树也符合这个条件。他的遍历方式和普通二叉树的遍历没有什么区别。

下面是关于二叉搜索树的添加节点和前序遍历,中序遍历, 后续遍历和层级遍历

 1 //递归创建添加新节点
 2 void insertNode(PNode *root, ItemType data)
 3 {
 4     if(*root == NULL)
 5     {
 6         *root = (PNode)malloc(sizeof(Node));
 7         (*root)->data = data;
 8         (*root)->lchild = (*root)->rchild = NULL;
 9     }
10     else
11     {
12         if(data < (*root)->data)
13             insertNode(&(*root)->lchild, data);
14         else
15             insertNode(&(*root)->rchild, data);
16     }
17 }
18 //递归前序遍历
19 void preOrder(PNode root)
20 {
21     if(root == NULL)
22         return;
23     printf("%d ", root->data);
24     preOrder(root->lchild);
25     preOrder(root->rchild);
26 }
27 //递归中序遍历
28 void inOrder(PNode root)
29 {
30     if(root == NULL)
31         return;
32     inOrder(root->lchild);
33     printf("%d ", root->data);
34     inOrder(root->rchild);
35 }
36 //递归后续遍历
37 void postOrder(PNode root)
38 {
39     if(root == NULL)
40         return;
41     postOrder(root->lchild);
42     postOrder(root->rchild);
43     printf("%d ", root->data);
44 }
45 
46 
47 //层级遍历
48 void levelOrder(PNode root)
49 {
50     queue<PNode> q;
51     PNode p = root;
52     if(p != NULL)
53         q.push(p);
54     while(!q.empty())
55     {
56         p = q.front();
57         printf("%d ", p->data);
58         if(p->lchild != NULL)
59             q.push(p->lchild);
60         if(p->rchild != NULL)
61             q.push(p->rchild);
62         q.pop();
63     }
64 }

以上这些操作除了插入有点特殊之外和普通的二叉树没有什么区别,下面主要来说二叉树的非递归遍历方法, 其中包括前序,中序和后续。其中前序和中序差不多,比较好理解点。

前序主要就是打印出节点的值, 再将左子树入栈,出栈时再栈顶的遍历右子树。下面是代码的实现

 1 void preOrder_NonRecursion(PNode root)
 2 {
 3     stack<PNode> s;
 4     PNode p = root;
 5     while(p != NULL || !s.empty())
 6     {
 7         if(p != NULL)//如果存在,继续找他的左孩子
 8         {
 9             printf("%d ", p->data);
10             s.push(p);
11             p = p->lchild;
12         }
13         else//没有的话,将p指向栈顶的元素,出栈操作,继续找右孩子
14         {
15             p = s.top();
16             s.pop();
17             p = p->rchild;
18         }
19     }
20 }

非递归的中序遍历和前序差不多,就改变输出的值,因为前序遍历是先根再左再右, 而中序是左根右, 所以只是输出顺序不同了而已

 1 //非递归中序遍历
 2 void inOrder_NonRecursion(PNode root)
 3 {
 4     stack<PNode> s;
 5     PNode p = root;
 6     while(p != NULL || !s.empty())
 7     {
 8         if(p != NULL)//左孩子不为空就进栈,继续它的左孩子
 9         {
10             s.push(p);
11             p = p->lchild;
12         }
13         else//输出栈顶的元素,然后出栈,找它右兄弟(程序中是先找父亲,然后找父亲的右孩子)
14         {
15             p = s.top();
16             printf("%d ", p->data);
17             s.pop();
18             p = p->rchild;
19         }
20     }
21 }

非递归的后续遍历稍微比前序和中序复杂了一点,但也不是很复杂,因为后续遍历是先左后右再根的, 所以根是最后的,所以加了一个布尔变量来标记他的右子树遍历了没有,其它的和前序和中序没什么大的区别, bool变量为true的时候说明他的右子树还没有遍历。false是已经遍历过了

 1 void postOrder_NonRecursion(PNode root)
 2 {
 3     stack<pair<PNode, bool> > s;//用pair使s 的类型为PNode和bool的复合类型
 4     PNode p = root;
 5     while(p != NULL || !s.empty())
 6     {
 7         if(p != NULL)//如果当前节点不为空的话,入栈, 继续找它的左孩子
 8         {
 9             s.push(make_pair(p, false));//初始的时候没有遍历他的右子树
10             p = p->lchild;
11         }
12         else//否则去栈顶
13         {
14             if(s.top().second == false)//如果它的右子树没有没遍历
15             {
16                 s.top().second = true;//标记已经遍历过
17                 p = s.top().first->rchild;//遍历右子树
18             }
19             else//遍历过了,直接输出, 因为此时节点为当前树的根节点
20             {
21                 printf("%d ", s.top().first->data);
22                 s.pop();
23             }
24         }
25     }
26 }

还有就是求树的高度, 一般是用递归来实现, 递归比价好理解, 代码也比较简洁, 但是有时候也需要非递归方式来求,下面是递归方式求的, 比较简单

 1 //递归求树的深度
 2 int getDepth(PNode root)
 3 {
 4     int d1, d2;
 5     if(root == NULL)
 6         return 0;
 7     d1 = getDepth(root->lchild);
 8     d2 = getDepth(root->rchild);
 9     return (d1 > d2 ? d1 : d2) + 1;
10 }

非递归的方式求书的高度的思想是:一层一层的遍历, 当遍历一层的时候, 层数加一, 但是怎么确定这层是否遍历完呢, 这时就需要三个变量来合作记录了,一个last_level_number来记录以上层一共有多少个入队的, in_queue_number 来记录所有入队的了有几个, 还有一个是visit_number来记录当前已经出队了几个元素了, 也就是有多少个节点已经扩展了子节点, 也就是广搜的那个扩展, 主要还是利用层级遍历的思想, 需要一个队列

 1 //非递归求数的深度
 2 int getDepth_NonRecursion(PNode root)
 3 {
 4     if(root == NULL)
 5         return 0;
 6     queue<PNode> q;
 7     PNode p = root;
 8     q.push(p);
 9     int last_level_number = 1;//用来标记一共有多少个曾经入过队
10     int visit_number = 0;//记录已经扩展了的节点
11     int in_queue_number = 1;//所有入队的有所少个
12     int height = 0;
13     while (!q.empty())
14     {
15         visit_number++;//出队一次加一个, 也就是扩展一次, 加一次
16         p = q.front();
17         q.pop();
18         //分别扩展它的左孩子和右孩子
19         if (p->lchild != NULL)
20         {
21             q.push(p->lchild);
22             in_queue_number++;
23         }
24         if(p->rchild != NULL)
25         {
26             q.push(p->rchild);
27             in_queue_number++;
28         }
29         //如果到一层的结尾
30         if(visit_number == last_level_number)
31         {
32             height++;
33             last_level_number = in_queue_number;//更新last_level_number
34         }
35     }
36     return height;
37 }

还有就是求二叉搜索树中任意给定两个节点的最近的共同祖先, 这里是二叉搜索树比较简单, 如果不是二叉搜索树就比较麻烦了,暂时只说二叉搜索树的, 非二叉搜索树的后面补上。

主要思想是:利用二叉搜索树的性质, 任意的左孩子都比根节点小, 任意的右节点都比根节点大, 所以,直接拿着两个点和根节点进行比价, 如果都比根节点大的话, 就说明共同祖先肯定在根节点的右边, 如果都小的话, 就说明都在根节点的左边, 如果一小一大那就好办了, 直接就是根节点了, 继续找左子树或者右子树。下面是代码的实现'

//求两节点的最近的共同祖先
void getCommonAncestor(PNode root, ItemType n1, ItemType n2)
{
    if(root == NULL)
        return;
    while((n1 < root->data && n2 < root->data) || (n1 > root->data && n2 > root->data) )
    {
        if(n1 < root->data)
            root = root->lchild;
        else
            root = root->rchild;
    }
    printf("latest common ancestor: %d\n", root->data);
}

求二叉树的镜像,二叉树的镜像的意思就是将他的各个左右节点都反过来, 听着很麻烦, 其实递归很简单的, 只需要先把他的左右子树交换过来, 然后再继续递归他的左右子树就行了

代码如下:

 1 //求二叉树的镜像
 2 void mirror(PNode root)
 3 {
 4     if(root != NULL)
 5     {
 6         //交换它的左右子树
 7         PNode p = root->lchild;
 8         root->lchild = root->rchild;
 9         root->rchild = p;
10         //递归它的左右子树
11         mirror(root->lchild);
12         mirror(root->rchild);
13     }
14 }

 

下面是所有的实现的完整代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <math.h>
  4 #include <stack>
  5 #include <queue>
  6 
  7 using namespace std;
  8 
  9 typedef int ItemType;
 10 typedef struct Node{
 11     ItemType data;
 12     struct Node *lchild, *rchild;
 13 }Node, *PNode;
 14 //递归创建添加新节点
 15 void insertNode(PNode *root, ItemType data)
 16 {
 17     if(*root == NULL)
 18     {
 19         *root = (PNode)malloc(sizeof(Node));
 20         (*root)->data = data;
 21         (*root)->lchild = (*root)->rchild = NULL;
 22     }
 23     else
 24     {
 25         if(data < (*root)->data)
 26             insertNode(&(*root)->lchild, data);
 27         else
 28             insertNode(&(*root)->rchild, data);
 29     }
 30 }
 31 //递归前序遍历
 32 void preOrder(PNode root)
 33 {
 34     if(root == NULL)
 35         return;
 36     printf("%d ", root->data);
 37     preOrder(root->lchild);
 38     preOrder(root->rchild);
 39 }
 40 //递归中序遍历
 41 void inOrder(PNode root)
 42 {
 43     if(root == NULL)
 44         return;
 45     inOrder(root->lchild);
 46     printf("%d ", root->data);
 47     inOrder(root->rchild);
 48 }
 49 //递归后续遍历
 50 void postOrder(PNode root)
 51 {
 52     if(root == NULL)
 53         return;
 54     postOrder(root->lchild);
 55     postOrder(root->rchild);
 56     printf("%d ", root->data);
 57 }
 58 //非递归前序遍历
 59 void preOrder_NonRecursion(PNode root)
 60 {
 61     stack<PNode> s;
 62     PNode p = root;
 63     while(p != NULL || !s.empty())
 64     {
 65         if(p != NULL)//如果存在,继续找他的左孩子
 66         {
 67             printf("%d ", p->data);
 68             s.push(p);
 69             p = p->lchild;
 70         }
 71         else//没有的话,将p指向栈顶的元素,出栈操作,继续找右孩子
 72         {
 73             p = s.top();
 74             s.pop();
 75             p = p->rchild;
 76         }
 77     }
 78 }
 79 //非递归中序遍历
 80 void inOrder_NonRecursion(PNode root)
 81 {
 82     stack<PNode> s;
 83     PNode p = root;
 84     while(p != NULL || !s.empty())
 85     {
 86         if(p != NULL)//左孩子不为空就进栈,继续它的左孩子
 87         {
 88             s.push(p);
 89             p = p->lchild;
 90         }
 91         else//输出栈顶的元素,然后出栈,找它右兄弟(程序中是先找父亲,然后找父亲的右孩子)
 92         {
 93             p = s.top();
 94             printf("%d ", p->data);
 95             s.pop();
 96             p = p->rchild;
 97         }
 98     }
 99 }
100 //非递归后续遍历
101 void postOrder_NonRecursion(PNode root)
102 {
103     stack<pair<PNode, bool> > s;//用pair使s 的类型为PNode和bool的复合类型
104     PNode p = root;
105     while(p != NULL || !s.empty())
106     {
107         if(p != NULL)//如果当前节点不为空的话,入栈, 继续找它的左孩子
108         {
109             s.push(make_pair(p, false));//初始的时候没有遍历他的右子树
110             p = p->lchild;
111         }
112         else//否则去栈顶
113         {
114             if(s.top().second == false)//如果它的右子树没有没遍历
115             {
116                 s.top().second = true;//标记已经遍历过
117                 p = s.top().first->rchild;//遍历右子树
118             }
119             else//遍历过了,直接输出, 因为此时节点为当前树的根节点
120             {
121                 printf("%d ", s.top().first->data);
122                 s.pop();
123             }
124         }
125     }
126 }
127 //层级遍历
128 void levelOrder(PNode root)
129 {
130     queue<PNode> q;
131     PNode p = root;
132     if(p != NULL)
133         q.push(p);
134     while(!q.empty())
135     {
136         p = q.front();
137         printf("%d ", p->data);
138         if(p->lchild != NULL)
139             q.push(p->lchild);
140         if(p->rchild != NULL)
141             q.push(p->rchild);
142         q.pop();
143     }
144 }
145 //求一层的所有节点
146 void specifyLevelNode(PNode root, int h)//h是指定的高度
147 {
148     if(root == NULL)
149         return;
150     queue<PNode> q;
151     PNode p = root;
152     q.push(p);
153     int last_level_number = 1;//用来标记以上所有层多少个
154     int visit_number = 0;
155     int in_queue_number = 1;//入队的多少个
156     int height = 0;
157     while (!q.empty())
158     {
159         visit_number++;
160         p = q.front();
161         q.pop();
162 
163         if (p->lchild != NULL)
164         {
165             q.push(p->lchild);
166             in_queue_number++;
167             if (h - 2 == height)/*因为这个高度执行到后面才++, 所以h要减一,
168             还有就是当前是p->lchild而不是p,所以在减一*/
169                 printf("%d ", p->lchild->data);
170         }
171         if(p->rchild != NULL)
172         {
173             q.push(p->rchild);
174             in_queue_number++;
175             if (h - 2== height)//同上
176                 printf("%d ", p->rchild->data);
177         }
178 
179         if(visit_number == last_level_number)
180         {
181             height++;
182             last_level_number = in_queue_number;
183         }
184     }
185 }
186 //递归求树的深度
187 int getDepth(PNode root)
188 {
189     int d1, d2;
190     if(root == NULL)
191         return 0;
192     d1 = getDepth(root->lchild);
193     d2 = getDepth(root->rchild);
194     return (d1 > d2 ? d1 : d2) + 1;
195 }
196 //非递归求数的深度
197 int getDepth_NonRecursion(PNode root)
198 {
199     if(root == NULL)
200         return 0;
201     queue<PNode> q;
202     PNode p = root;
203     q.push(p);
204     int last_level_number = 1;//用来标记一共有多少个曾经入过队
205     int visit_number = 0;//记录已经扩展了的节点
206     int in_queue_number = 1;//所有入队的有所少个
207     int height = 0;
208     while (!q.empty())
209     {
210         visit_number++;//出队一次加一个, 也就是扩展一次, 加一次
211         p = q.front();
212         q.pop();
213         //分别扩展它的左孩子和右孩子
214         if (p->lchild != NULL)
215         {
216             q.push(p->lchild);
217             in_queue_number++;
218         }
219         if(p->rchild != NULL)
220         {
221             q.push(p->rchild);
222             in_queue_number++;
223         }
224         //如果到一层的结尾
225         if(visit_number == last_level_number)
226         {
227             height++;
228             last_level_number = in_queue_number;//更新last_level_number
229         }
230     }
231     return height;
232 }
233 //求二叉树中相距最远的两个节点之间的距离
234 int getMaxDistance(PNode root)
235 {
236     if(root == NULL)
237         return 0;
238     return getDepth(root->lchild) + getDepth(root->rchild);
239 }
240 //求两节点的最近的共同祖先
241 void getCommonAncestor(PNode root, ItemType n1, ItemType n2)
242 {
243     if(root == NULL)
244         return;
245     while((n1 < root->data && n2 < root->data) || (n1 > root->data && n2 > root->data) )
246     {
247         if(n1 < root->data)
248             root = root->lchild;
249         else
250             root = root->rchild;
251     }
252     printf("latest common ancestor: %d\n", root->data);
253 }
254 
255 //求路径和为指定值的所有路径
256 
257 int main()
258 {
259 
260     PNode root = NULL;
261     int test[8] = {8, 5, 16, 1, 4, 9, 24, 7};
262     for(int i = 0; i < 8; i++)
263     {
264         insertNode(&root, test[i]);
265     }
266     printf("Previous Order Traverse:\n");
267     preOrder(root);
268     printf("\nIn Order Traverse:\n");
269     inOrder(root);
270     printf("\nPost Order Traverse:\n");
271     postOrder(root);
272     printf("\nNon-Recursion Previous Order Traverse:\n");
273     preOrder_NonRecursion(root);
274     printf("\nNon-Recursion In Order Traverse:\n");
275     inOrder_NonRecursion(root);
276     printf("\nNon-Recursion Post Order Traverse:\n");
277     postOrder_NonRecursion(root);
278     printf("\nLevel Order Traverse:\n");
279     levelOrder(root);
280     printf("\nThe depth of tree: %d\n", getDepth(root));
281     printf("The depth of tree(Non-Recursion): %d\n", getDepth_NonRecursion(root));
282     specifyLevelNode(root, 3);//求第三层的所有节点
283     printf("\nThe max distance: %d\n", getMaxDistance(root));
284     getCommonAncestor(root, 7, 4);//测试数据,得出7和4的最近祖先
285 
286     return 0;
287 }

 

posted @ 2014-10-19 21:37  Howe_Young  阅读(334)  评论(0编辑  收藏  举报