C语言树形打印二叉树

学习二叉树时,如果能直观显示,测试程序的时候会方便许多。

实现树形打印的标准方法是利用队列,此处参考的是CSDN上的一篇文章:树状显示二叉树, 原程序使用C++实现,这里使用C。

算法中使用了两个队列,一个用于存储树的结点,另一个用于存储打印过程中每个结点对应的信息。

上一篇文章写了可以利用 void 指针来实现模板,这一次嫌麻烦没有用这个方法,复制粘贴了两个队列。

改天试一试能不能把 void 指针的赋值抽象成一套函数来用用。

如同上面那篇文章中介绍的,此打印程序的核心思想是利用父结点的坐标 pos, 和每一层的偏移量 offset 计算左右子结点的位置。

左结点的坐标是 pos - offset, 右结点的坐标是 pos + offset.

实现代码如下:

 1 // content of "BST.h"
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4
 5 // definition of the Tree.
 6
 7 struct Node {
 8     int key;
 9     struct Node *LeftChild;
10     struct Node *RightChild;
11 };
12
13 typedef struct Node *Position;
14 typedef struct Node *SearchTree;
15
16 int GetHeight(SearchTree T);
17 SearchTree Insert(SearchTree T, int data);
18 Position Find(SearchTree T, int data);
19 SearchTree Delete(SearchTree T, int data);
20 Position FindMin(SearchTree T);
21
22 void Error1(char *s);
23
24 // Definition of the Queue of Nodes.
25
26 typedef Position ElementType;
27
28 struct Q_Item {
29     ElementType data;
30     struct Q_Item *next;
31 };
32
33 typedef struct Q_Item *PtrToItem;
34
35 struct Qrec {
36     PtrToItem front, end;
37 };
38
39 typedef struct Qrec *Queue;
40
41 Queue CreateQ(void);
42 void InQ(Queue Q, ElementType data);
43 ElementType OutQ(Queue Q);
44 void Clear(Queue Q);
45 int IsEmpty(Queue Q);
46 int Power(int x, int n);
47
48 // Definition of the Queue of the info needed in PrintDepth.
49
50 struct infoNode {
51     int pos;
52     int space;
53     int level;
54     int newline;
55     struct infoNode *next;
56 };
57
58 typedef struct infoNode *infoItem;
59
60 struct infoQrec {
61     infoItem front, end;
62 };
63
64 typedef struct infoQrec *infoQ;
65
66 infoItem MakeItem(int pos, int space, int level, int newline);
67 infoQ CreateInfoQ(void);
68 void Pushback(infoQ Q, infoItem item);
69 infoItem PopFront(infoQ Q);
70 int InfoQEmpty(infoQ Q);
71
72 // the final function is here
73 75 void PrintDepth_2(SearchTree T);
  1 #include"BST.h"
  2 #define TRUE 1
  3 #define FALSE 0
  4
  5 // the Queue of TreeNodes.
  6
  7 Queue CreateQ(void)
  8 {
  9     Queue Q = (Queue)malloc(sizeof(struct Qrec));
 10     if(!Q)
 11         Error1("out of space for Queue for TreeNode");
 12
 13     Q->front = Q->end = NULL;
 14
 15     return Q;
 16 }
 17
 18 void InQ(Queue Q, ElementType data)
 19 {
 20     PtrToItem newNode = (PtrToItem)malloc(sizeof(ElementType));
 21     if(!newNode)
 22     {
 23         printf("no space for newNode\n");
 24         exit(1);
 25     }
 26
 27     newNode->data = data;
 28     newNode->next = NULL;
 29
 30     if(!Q->end)
 31         Q->front = Q->end = newNode;
 32     else
 33     {
 34         Q->end->next = newNode;
 35         Q->end = newNode;
 36     }
 37 }
 38
 39 ElementType OutQ(Queue Q)
 40 {
 41     ElementType data;
 42     PtrToItem temp;
 43
 44     if(!Q->front)
 45     {
 46         printf("the Queue is empty\n");
 47         exit(1);
 48     }
 49
 50     temp = Q->front;
 51     data = temp->data;
 52
 53     if(temp->next == NULL)
 54         Q->front = Q->end = NULL;
 55     else
 56         Q->front = temp->next;
 57
 58     free(temp);
 59
 60     return data;
 61 }
 62
 63 void Clear(Queue Q)
 64 {
 65     PtrToItem curr, temp;
 66
 67     curr = Q->front;
 68
 69     while(curr)
 70     {
 71         temp = curr;
 72         curr = curr->next;
 73         free(temp);
 74     }
 75
 76     free(Q);
 77
 78 }
 79
 80 int IsEmpty(Queue Q)
 81 {
 82     return Q->front == NULL;
 83 }
 84
 85 int Power(int x, int n)
 86 {
 87     if(n == 0)
 88         return 1;
 89     else if( n % 2 )
 90         return Power(x*x, n/2) * x;
 91     else
 92         return Power(x*x, n/2);
 93 }
 94
 95 // the Queue for printing information.
 96
 97 infoItem MakeItem(int pos, int space, int level, int newline)
 98 {
 99     infoItem newItem = (infoItem)malloc(sizeof(struct infoNode));
100     if(!newItem)
101         Error1("out of space for infoNode");
102
103     newItem->pos = pos;
104     newItem->space = space;
105     newItem->level = level;
106     newItem->newline = newline;
107     newItem->next = NULL;
108
109     return newItem;
110 }
111
112 infoQ CreateInfoQ(void)
113 {
114     infoQ Q = (infoQ)malloc(sizeof(struct infoQrec));
115     if(!Q)
116         Error1("out of space for infoQ");
117
118     Q->front = Q->end = NULL;
119
120     return Q;
121 }
122
123 void Pushback(infoQ Q, infoItem item)
124 {
125     infoItem newItem = item;
126
127     if(!Q->end)
128         Q->front = Q->end = newItem;
129     else
130     {
131         Q->end->next = newItem;
132         Q->end = newItem;
133     }
134 }
135
136 infoItem PopFront(infoQ Q)
137 {
138     infoItem item;
139
140     if(!Q->front)
141         Error1("the Queue is empty");
142
143     item = Q->front;
144
145     if(item->next == NULL)
146         Q->front = Q->end = NULL;
147     else
148         Q->front = item->next;
149
150     return item;
151 }
152
153 void ClearInfoQ(infoQ Q)
154 {
155     infoItem curr, temp;
156
157     curr = Q->front;
158
159     while(curr)
160     {
161         temp = curr;
162         curr = curr->next;
163         free(temp);
164     }
165
166     free(Q);
167
168 }
169
170 int InfoQEmpty(infoQ Q)
171 {
172     return Q->front == NULL;
173 }
174
175
176
177 // this function also print the NULL nodes,
178 // so the tree will look better and prettier,
179 // but also acquire a larger screen because
180 // this function divides the screen into
181 // many blocks, so the space here is consuming.
182 //
183 // |  |  |  |44|  |  |  |
184 // |  |29|  |  |  |66|  |
185 // |11|  |33|  |54|  |77|
186 //
187 // the key idea of this program is:
188 // while the node is not at the bottom,
189 // no matter if there is a node in the tree,
190 // we create a infoItem with the printing information,
191 // and push a NULL into the Queue.
192 // when we pop the elements out of the Queue,
193 // if the Node it contains is a NULL, we print some
194 // blank block, otherwise we print the key in the Node.
195
196
197 void PrintDepth(SearchTree T)
198 {
199     Position currNode;
200     Queue Q = CreateQ();
201     infoQ IQ = CreateInfoQ();
202     infoItem newInfo, currInfo, preInfo;
203     int height = GetHeight(T);
204     int ScreenWidth = Power(2, height+1);
205     int pos, level, space, newline;
206     int dataWidth = 1;    // dataWidth is the width of the block.
207     int i;
208
209     InQ(Q, T);
210     level = 1;
211     pos = ScreenWidth >> level;
212     space = pos;
213     newline = TRUE;
214
215     newInfo = MakeItem(pos, space, level, newline);
216     Pushback(IQ, newInfo);
217
218     preInfo = newInfo;
219
220     while(!IsEmpty(Q))
221     {
222         currNode = OutQ(Q);
223         currInfo = PopFront(IQ);
224
225         if(currInfo->newline)
226             printf("\n");
227
228         for(i=0; i<currInfo->space; i++)
229             printf(" ");
230
231         if(currNode)
232             printf("%d",currNode->key);
233         else
234             printf(" ");
235
236         if(currInfo->level < height+1)   // if the node is not at the bottom,
237         {                    //  always create 2 child nodes.
238             level = currInfo->level + 1;
239             pos = currInfo->pos - (ScreenWidth >> level);  // the left child.
240             if(level > preInfo->level)
241             {
242                 newline = TRUE;
243                 space = pos;
244             }
245             else
246             {
247                 newline = FALSE;
248                 space = pos - preInfo->pos;
249             }
250
251             space--;       // set aside space for the data to be printed.
252             newInfo = MakeItem(pos, space, level, newline);
253
254             Pushback(IQ, newInfo);
255
256             preInfo = newInfo;
257
258             if(currNode)  // if there is a node in a tree, create the left child.
259             {
260                 if(currNode->LeftChild)
261                     InQ(Q, currNode->LeftChild);
262                 else
263                     InQ(Q, NULL);
264             }
265             else      // if there is a NULL, create the "left child" for NULL.
266                 InQ(Q, NULL);
267
268             pos = currInfo->pos + (ScreenWidth >> level); // the right child.
269             newline = FALSE;
270             space = pos - preInfo->pos;
271             space--;
272
273             newInfo = MakeItem(pos, space, level, newline);
274
275             Pushback(IQ, newInfo);
276
277             if(currNode)
278             {
279                 if(currNode->RightChild)
280                     InQ(Q, currNode->RightChild);
281                 else
282                     InQ(Q, NULL);
283             }
284             else
285                 InQ(Q, NULL);
286
287             preInfo = newInfo;
288
289         }
290
291     }
292
293     printf("\n\n");
294 }
时间: 2024-10-19 05:44:49

C语言树形打印二叉树的相关文章

反转二叉树 打印二叉树

代码: package com.qhong; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { TreeNode root =new TreeNode(0); TreeNode left=new TreeNode(1); TreeNode right=new Tre

【Java】 剑指offer(31)从上往下打印二叉树

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 (一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印. (二)从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行. (三)请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推. 思路 (一)不分行从上往下打印二叉树:该题即为对二叉树的层

按之字形顺序打印二叉树

题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推 /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ class Solution { public: vector<vect

从上往下打印二叉树(分层遍历)

从上往下打印二叉树的每个节点,同一层的节点按照从左到右的顺序打印. 从上到下打印二叉树的规律:每一次打印一个节点的时候,如果该节点有子节点,则把该节点的子节点放到一个队列的末尾.接下来到队列的头部取出最早进入队列的节点,重复前面的打印操作,直到队列中所有的节点都被打印出来为止. struct TreeNode { int val; TreeNode* left; TreeNode* right; }; void LevelOrder(BinaryTreeNode* root) { if (roo

剑指Offer面试题23(Java版):从上往下打印二叉树

题目:从上往下打印二叉树的每个结点,同一层的结点按照从左到右的顺序打印.例如输入下图的二叉树,则一次打印出8,6,10,5,7,9,11. 这道题实质上考察的就是树的遍历算法,只是这种遍历不是我们熟悉的前序.中序或者后序遍历.由于我们不太熟悉这种按层遍历的方法,可能已下载也想不清楚遍历的过程. 因为按层打印的顺序决定应该先打印的根节点,所以我们从树的根节点开始分析.为了接下来能够打印8的结点的两个子节点,我们应该在遍历到该结点时把值为6和10的两个结点保存到一个容器中,现在容器内就有两个结点了.

打印二叉树节点数值总和等于某个给定节点的所有路径

打印二叉树节点数值总和等于某个给定节点的所有路径,路径可以从任意节点开始,任意节点结束. 比如,假设和是8,树如下 的路径有  [[5,3],[8],[5,1,2]].  5  / \ 3     1 /\     /\ 4  8  2   6 思路:遍历所有路径,对于每一个节点,在其路径中向后寻找sum和为target的路径加入到结果中. public List<List<Integer>> findSum(TreeNode root,int sum){ List<List

剑指OFFER之从上往下打印二叉树(九度OJ1523)

题目描述: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行一个整数n(1<=n<=1000, :n代表将要输入的二叉树元素的个数(节点从1开始编号).接下来一行有n个数字,代表第i个二叉树节点的元素的值.接下来有n行,每行有一个字母Ci.Ci='d'表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号.Ci='l'表示第i个节点有一个左孩子,紧接着是左孩子的编号.Ci='r'表示第i个节点有一个右孩

算法笔记_189:历届试题 横向打印二叉树(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 二叉树可以用于排序.其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树. 当遇到空子树时,则把该节点放入那个位置. 比如,10 8 5 7 12 4 的输入顺序,应该建成二叉树如下图所示,其中.表示空白. ...|-1210-|...|-8-|.......|...|-7.......|-5-|...........|-4 本题目要求:根据已知的数字,建立排序二叉树,并在标准输出中横

按之字形顺序打印二叉树-剑指Offer

按之字形顺序打印二叉树 题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. 思路 根据题意,每行的节点的访问顺序是相反的,我们可以用两个栈来隔行存储,一个栈中根据“左结点->右结点”的顺序访问另一个栈的栈顶元素,而另一个栈根据“右子树->左子树”的顺序访问另一个栈的栈顶元素,直到两个栈都为空 代码 import java.util.ArrayList; import java.util.St