1. 程式人生 > 實用技巧 >新浪)微博發)帖軟(件 資料結構第三節(樹(上))

新浪)微博發)帖軟(件 資料結構第三節(樹(上))

樹是一種基本的層次結構,相比線性結構,在動態查詢上,效率更高。
在說樹之前,我們先說一下線性結構中兩種常用的查詢方式。

兩種查詢方式順序查詢和二分查詢#

順序查詢(哨兵法)#

對於一個線性表方便的查詢方式是,從後向前查詢且將被查詢的值放在最前面作為哨兵,只需要判斷下標位置的元素是否為查詢元素,而不用考慮下標是否走到邊界(因為邊界元素正好是我們的哨兵,走到了這裡自動退出)

程式碼實現:

Copy
#include<stdio.h>
#include<stdlib.h>

typedef struct LNode* List;
#define MAXSIZE 100
#define ElementType int
struct LNode
{
	ElementType Data[MAXSIZE];
	int length;
};

int sequentailSearch(List L,ElementType key) {
	int i = 0;
	L->Data[0] = key;//建立哨兵
	for (i = L->length; L->Data[i] != key; i--);
	return i;//找到返回對應下標,沒找到返回0
}

二分查詢#

想對一個線性表使用二分查詢,他必須是有序的

例如有一個線性表從小到大排列,設定兩個變數(left和right)分別設為線性表的兩端下標,通過比較中間位置的值於被查詢元素的值,改變2個變數的指向,如果中間的值大於被查到元素,說明被查詢元素應該在中間的右側,我們將right設為中間的位置下標減1,同理....

程式碼實現:

Copy
#include<stdio.h>
#include<stdlib.h>

typedef struct LNode* List;
#define MAXSIZE 100
#define ElementType int
struct LNode
{
	ElementType Data[MAXSIZE];
	int length;
};
//從小到大排序的情況
int binarySearch(List L, ElementType key) {
	int left = 1, right = L->length;
	while (left <= right) {
		int mid = (left + right) / 2;
		//如果mid下標的元素大於要找的,說明在left-mid之間,顧使right = mid-1。
		if (L->Data[mid] > key) {
			right = mid - 1;
		}
		else if (L->Data[mid] < key) {
			left = mid + 1;
		}
		else {
			return mid;
		}
	}
	return -1;//查詢失敗返回-1
}

#

樹是一種抽象資料型別或是實現這種抽象資料型別的資料結構,用來模擬具有樹狀結構性質的資料集合。它是由n(n>0)個有限節點組成一個具有層次關係的集合。n = 0時為空樹。

非空樹的性質#

1.只含有一個根節點
2.其餘的節點分成多個不相交的節點哪個節點又是原樹的子樹
3.子樹互不相交,除根節點外所有節點都有一個父節點
4.N個節點的數有N-1條邊

樹的一些基本術語#

1.結點的度(Degree):結點的子樹個數
2.樹的度:樹的所有結點中最大的度數
3.葉結點(Leaf):度為0的結點
4.父結點(Parent):有子樹的結點是其子樹的根結點的父結點
5.子結點(Child):若A結點是B結點的父結點,則稱B結點是A結點的子結點;子結點也稱孩子結點。
6.兄弟結點(Sibling):具有同一父結點的各結點彼此是兄弟結點。
7.路徑和路徑長度:從結點

n1n1到nknk的路徑為一個結點序列n1n1,n2n2,… ,nknk,nini是ni+1ni+1的父結點。路徑所包含邊的個數為路徑的長度。
9.祖先結點(Ancestor):沿樹根到某一結點路徑上的所有結點都是這個結點的祖先結點。
10.子孫結點(Descendant):某一結點的子樹中的所有結點是這個結點的子孫。
11.結點的層次(Level):規定根結點在1層,其它任一結點的層數是其父結點的層數加1。
12.樹的深度(Depth):樹中所有結點中的最大層次是這棵樹的深度。

二叉樹(一種特殊的樹)#

對於一個二叉樹,他的任何節點最多有兩個子樹,分別為左子樹和右子樹,二叉樹的分支具有左右次序,不能隨意顛倒。

三種特殊的二叉樹#

二叉樹的性質#

1.第i層最多有2i12i−1個節點
2.深度為k的樹最多有2k12k−1個節點
3.對於一個非空二叉樹用nnk(k∈0,1,2)表示有幾個兒子的節點。有等式n0n0=n2n2+ 1 恆成立。
證: 樹的總邊數 =n0n0+n1n1+n2n2- 1(除了根節點外每個節點都有父節點)
樹的總邊數 = 0 *n0n0+ 1 *n1n1+ 2 *n2n2(節點的下標代表了他有幾個兒子也就是幾條邊)
聯立可得n0n0=n2n2+ 1

二叉樹的實現#

如果採用線性的儲存方法,儲存在陣列中,根據上面的二分查詢我們可以知道,二分查詢順序固定,可以行的通,但對於不是完美二叉樹,會在空間上造成浪費,並不推薦。
常用的做法是採用鏈式儲存下面給出樹節點程式碼實現

Copy
struct TreeNode
{
	ElementType Data;
	BinTree Left;//指向左子樹
	BinTree Right;//指向右子樹
};

二叉樹的遍歷#

對於一顆二叉樹,我們經常希望訪問樹中的每一個結點並且檢視它的值。有很多常見的順序來訪問所有的結點,而且每一種都有有用的性質。
這裡介紹基於深度的前序中序後序遍歷
對一棵樹前序遍歷,就是先訪問它的根節點,再訪問他的左子樹,再訪問他的右子樹。
對一棵樹中序遍歷,就是先訪問他的左子樹,再訪問它的根節點,再訪問他的右子樹。
對一棵樹後序遍歷,就是先訪問他的左子樹,再訪問他的右子樹,再訪問它的根節點。

不難看出這三種遍歷方式都可以用遞迴來實現,下面給出程式碼實現

Copy
#include<stdio.h>
#include<stdlib.h>

typedef struct TreeNode* BinTree;
#define ElementType int
struct TreeNode
{
	ElementType Data;
	BinTree Left;
	BinTree Right;
};

//先序遍歷
void PreOrderTraversal(BinTree T) {
	//如果是空樹就不遍歷
	if (T) {
		printf("%d ", T->Data);
		PreOrderTraversal(T->Left);
		PreOrderTraversal(T->Right);
	}
}

//中序遍歷
void InOrderTraversal(BinTree T) {
	//如果是空樹就不遍歷
	if (T) {
		InOrderTraversal(T->Left);
		printf("%d ", T->Data);
		InOrderTraversal(T->Right);
	}
}

//後序遍歷
void PostOrderTraversal(BinTree T) {
	//如果是空樹就不遍歷
	if (T) {
		PostOrderTraversal(T->Left);
		PostOrderTraversal(T->Right);
		printf("%d ", T->Data);
	}
}

通常情況下,用遞迴實現的方法都可以用迴圈來實現,對於三種遍歷方法也是,仔細觀察樹遍歷的路線圖,不難發現,所走的路線是一樣的,只是丟擲的時機不同,前序遇到就丟擲,中序遇到第2次掏出,後續第三次丟擲,根據這種特性我們可以通過堆疊來實現。

Copy
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

typedef struct SNode* Stack;
typedef struct TreeNode* BinTree;
#define ElementType1 int
#define ElementType2 BinTree
struct TreeNode
{
	ElementType1 Data;
	BinTree Left;
	BinTree Right;
};
struct SNode
{
	ElementType2 Data;
	Stack Next;
};

//get link stack length,the empty stack has a header, the default length is 0
int length(Stack ptrs) {
	Stack temp = ptrs;
	int len = 0;
	while (temp->Next) {
		temp = temp->Next;
		len++;
	}
	return len;
}
//make an empty linked Stack,generate an empty header(length is 1)
Stack makeEmpty() {
	Stack ptrs;
	ptrs = (Stack)malloc(sizeof(struct SNode));
	ptrs->Next = NULL;
	return ptrs;
}
//check the linklist is empty
bool isEmpty(Stack ptrs) {
	if (length(ptrs) == 0) {
		return true;
	}
	else {
		return false;
	}
}
//push
Stack push(ElementType2 value, Stack ptrs) {
	Stack newLNode = (Stack)malloc(sizeof(struct SNode));
	newLNode->Data = value;
	newLNode->Next = ptrs->Next;
	ptrs->Next = newLNode;
	return ptrs;
}
//pop
ElementType2 pop(Stack ptrs) {
	if (isEmpty(ptrs)) {
		printf("the Stack has been empty.");
		return NULL;
	}
	Stack temp = ptrs->Next;
	ElementType2 value = temp->Data;
	ptrs->Next = temp->Next;
	free(temp);
	return value;
}
//先序遍歷
void PreOrderTraversal(BinTree T) {
	Stack S = makeEmpty();
	BinTree BT = T;
	while (BT || !isEmpty(S)) {
		while (BT) {
			printf("%d ", BT->Data);
			S = push(BT, S);
			BT = BT->Left;
		}
		if (!isEmpty(S)) {
			BT = pop(S);
			BT = BT->Right;
		}
	}
}

//中序遍歷
void InOrderTraversal(BinTree T) {
	Stack S = makeEmpty();
	BinTree BT = T;
	while (BT || !isEmpty(S)) {
		while (BT) {
			S = push(BT, S);
			BT = BT->Left;
		}
		if (!isEmpty(S)) {
			BT = pop(S);
			printf("%d ", BT->Data);
			BT = BT->Right;
		}
	}
}

//後序遍歷
void PostOrderTraversal(BinTree T) {
	Stack S = makeEmpty();
	BinTree BT = T;
	while (BT || !isEmpty(S)) {
		while (BT) {
			S = push(BT, S);
			BT = BT->Left;
		}
		if (!isEmpty(S)) {
			BT = pop(S);
			if (BT->Right) {
				S = push(BT, S);	
			}
			else {
				printf("%d ", BT->Data);
			}
			BT = BT->Right;
		}
	}
}

還有廣度優先遍歷,和深度優先遍歷不同,廣度優先遍歷會先訪問離根節點最近的節點。二叉樹的廣度優先遍歷又稱按層次遍歷。演算法藉助佇列實現。
基本思路為,先把根節點入隊,再讓根節點出隊,然後將根結點的左右子樹入隊,一直到佇列空就遍歷完成整個樹。

程式碼實現:

Copy
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

typedef struct QNode* Queue;

typedef struct TreeNode* BinTree;
#define ElementType1 int
#define ElementType2 BinTree
struct TreeNode
{
	ElementType1 Data;
	BinTree Left;
	BinTree Right;
};
struct QNode
{
	ElementType2 Data;
	Queue Next;
};

Queue makeEmpty() {
	Queue Q = (Queue)malloc(sizeof(struct QNode));
	Q->Next = NULL;
	return Q;
}

void QueueAdd(ElementType2 value, Queue Q) {
	Queue temp = Q->Next;
	Queue newNode = (Queue)malloc(sizeof(struct QNode));
	newNode->Data = value;
	newNode->Next = temp;
	Q->Next = newNode;
}

bool isEmpty(Queue Q) {
	if (Q->Next == NULL) {
		return true;
	}
	return false;
}
ElementType2 QueueDelete(Queue Q) {
	Queue ptrq = Q;
	if (!ptrq->Next) {
		printf("The queue has been empty.");
		return NULL;
	}
	while (ptrq->Next->Next) {
		ptrq = ptrq->Next;
	}
	Queue temp = ptrq->Next;
	ptrq->Next = NULL;
	ElementType2 value = temp->Data;
	free(temp);
	return value;
}
//層序遍歷
void LevelOrderTraversal(BinTree T) {
	//空樹直接退出
	if (!T) {
		return;
	}
	Queue Q = makeEmpty();
	QueueAdd(T, Q);//先把根節點壓入佇列
	while (!isEmpty(Q)) {
		BinTree BT = QueueDelete(Q);//出隊
		printf("%d ", BT->Data);
		//如果該節點左右還有節點就壓入佇列
		if (BT->Left) {
			QueueAdd(BT->Left, Q);
		}
		if (BT->Right) {
			QueueAdd(BT->Right, Q);
		}
	}

課後練習題(3個小題)#

03-樹1 樹的同構 (25point(s))#

給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因為我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。

現給定兩棵樹,請你判斷它們是否是同構的。
輸入格式:
輸入給出2棵二叉樹樹的資訊。對於每棵樹,首先在一行中給出一個非負整數N (≤10),即該樹的結點數(此時假設結點從0到N−1編號);隨後N行,第i行對應編號第i個結點,給出該結點中儲存的1個英文大寫字母、其左孩子結點的編號、右孩子結點的編號。如果孩子結點為空,則在相應位置上給出“-”。給出的資料間用一個空格分隔。注意:題目保證每個結點中儲存的字母是不同的。

輸出格式:
如果兩棵樹是同構的,輸出“Yes”,否則輸出“No”。

輸入樣例1(對應圖1):

8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -

輸出樣例1:

Yes

輸入樣例2(對應圖2):

8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -
H - -
C 0 2
G - 3
F - -
A 1 4

輸出樣例2:

No

程式碼實現:

Copy
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define ElemrnntType char
#define MAXSIZE 10
#define Null -1
struct TreeNode
{
	ElemrnntType Data;
	int Left;
	int Right;
}T1[MAXSIZE],T2[MAXSIZE];

int buildTree(struct TreeNode T[]) {
	int N = 0;
	int root = -1;
	//注意看重點,一定要在這裡讀取加\n,要不會自閉的
	scanf("%d\n", &N);
	//用來檢查哪個元素是根,預設都是0,在讀入節點時,有指向的位置就不是
	int check[MAXSIZE] = {0};
	for (int i = 0; i < N;i++) {
		char left, right ,data;
		scanf("%c %c %c\n", &data, &left, &right);
		T[i].Data = data;
		T[i].Left = (left == '-') ? Null : (check[left - '0'] = 1, left - '0');
		T[i].Right = (right == '-') ? Null : (check[right - '0'] = 1, right - '0');
	}
	for (int i = 0; i < N;i++) {
		if (check[i] == 0) {
			root = i;
			break;
		}
	}
	//返回根節點
	return root;
}
//採用遞迴演算法,每次傳入一個樹的子樹作為新樹
bool IsomorphicTree(int root1,int root2) {
	//如果都是空的返回true
	if (root1==Null&&root2==Null) {
		return true;
	}
	//如果只有一顆空樹返回false
	if ((root1 == Null && root2 != Null)||(root1 != Null && root2 == Null)) {
		return false;
	}
	//如果根節點不同返回false, 相同則進行下一次遞迴判別
	if (T1[root1].Data != T2[root2].Data){
		return false;
	}
	else {
		//判斷左右交換和沒換隻要有一種成立就返回true
		return (IsomorphicTree(T1[root1].Left, T2[root2].Left) && IsomorphicTree(T1[root1].Right, T2[root2].Right)) ||
			(IsomorphicTree(T1[root1].Left, T2[root2].Right) && IsomorphicTree(T1[root1].Right, T2[root2].Left));
	}
}
int main() {
	//讀取2顆樹
	int root1 = buildTree(T1);
	int root2 = buildTree(T2);
	//判別是否為異構樹
	if (IsomorphicTree(root1, root2)) {
		printf("Yes\n");
	}
	else {
		printf("No\n");
	}
}

03-樹2 List Leaves (25point(s))#

Given a tree, you are supposed to list all the leaves in the order of top down, and left to right.

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤10) which is the total number of nodes in the tree -- and hence the nodes are numbered from 0 to N−1. Then N lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a "-" will be put at the position. Any pair of children are separated by a space.

Output Specification:
For each test case, print in one line all the leaves' indices in the order of top down, and left to right. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.

Sample Input:

Copy
8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6

Sample Output:

4 1 5

題目的意思就是傳入一個樹,要對該樹層序遍歷的順序,打印出他的所有葉節點,與上一題一樣,注意找出根節點。

Copy
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

typedef struct QNode* Queue;

#define MAXSIZE 10
#define Null -1
struct TreeNode
{
	int Left;
	int Right;
}T[MAXSIZE];
struct QNode
{
	int index;
	Queue Next;
};

Queue makeEmpty() {
	Queue Q = (Queue)malloc(sizeof(struct QNode));
	Q->Next = NULL;
	return Q;
}

void QueueAdd(int value, Queue Q) {
	Queue temp = Q->Next;
	Queue newNode = (Queue)malloc(sizeof(struct QNode));
	newNode->index = value;
	newNode->Next = temp;
	Q->Next = newNode;
}

bool isEmpty(Queue Q) {
	if (Q->Next == NULL) {
		return true;
	}
	return false;
}
int QueueDelete(Queue Q) {
	Queue ptrq = Q;
	if (!ptrq->Next) {
		printf("The queue has been empty.");
		return -1;
	}
	while (ptrq->Next->Next) {
		ptrq = ptrq->Next;
	}
	Queue temp = ptrq->Next;
	ptrq->Next = NULL;
	int value = temp->index;
	free(temp);
	return value;
}
int buildTree(struct TreeNode T[]) {
	int N = 0;
	int root = -1;
	//注意看重點,一定要在這裡讀取加\n,要不會自閉的
	scanf("%d\n", &N);
	//用來檢查哪個元素是根,預設都是0,在讀入節點時,有指向的位置就不是
	int check[MAXSIZE] = { 0 };
	for (int i = 0; i < N; i++) {
		char left, right, data;
		scanf("%c %c\n", &left, &right);
		T[i].Left = (left == '-') ? Null : (check[left - '0'] = 1, left - '0');
		T[i].Right = (right == '-') ? Null : (check[right - '0'] = 1, right - '0');
	}
	for (int i = 0; i < N; i++) {
		if (check[i] == 0) {
			root = i;
			break;
		}
	}
	//返回根節點
	return root;
}
//層序遍歷出葉節點
void LevelOrderTraversal(int root) {
	//空樹直接退出
	if (root==-1) {
		return;
	}
	bool isfrist = true;
	Queue Q = makeEmpty();
	QueueAdd(root, Q);//先把根節點壓入佇列
	while (!isEmpty(Q)) {
		root = QueueDelete(Q);//出隊
		//葉節點就丟擲
		if ((T[root].Left == -1)&& (T[root].Right == -1)) {
			if (isfrist) {
				printf("%d", root);
				isfrist = false;
			}
			else {
				printf(" %d", root);
			}
		}
		//如果該節點左右還有節點就壓入佇列
		if (T[root].Left !=-1) {
			QueueAdd(T[root].Left, Q);
		}
		if (T[root].Right !=-1) {
			QueueAdd(T[root].Right, Q);
		}
	}
}

int main() {
	//讀取樹
	int root = buildTree(T);
	//層序遍歷葉節點
	LevelOrderTraversal(root);
}

03-樹3 Tree Traversals Again (25point(s))#

An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.

Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to N). Then 2N lines follow, each describes a stack operation in the format: "Push X" where X is the index of the node being pushed onto the stack; or "Pop" meaning to pop one node from the stack.

Output Specification:
For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop

Sample Output:

3 4 2 6 5 1

題目的大意根據堆疊的順序得到樹,得到他的後序遍歷,仔細觀察不難發現,push的順序對應了前序遍歷,pop的順序對應了中序遍歷,所以對於該題的解法為,先將前序遍歷順序和中序遍歷順序儲存在陣列中,再根據前序遍歷和中序遍歷推匯出後序遍歷。因為後序遍歷為左右根,所以可以採用堆疊的方法的,先將樹的根堆入,再堆入右子樹,再堆入左子樹,遞迴完成。

程式碼實現:

Copy
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

#define MAXSIZE 30
#define ElementType char
typedef struct SNode* Stack;
#define ElementType char
struct SNode
{
	ElementType Data;
	Stack Next;
};
char PreOrderTraversal[MAXSIZE];
char InOrderTraversal[MAXSIZE];
//get link stack length,the empty stack has a header, the default length is 0
int length(Stack ptrs) {
	Stack temp = ptrs;
	int len = 0;
	while (temp->Next) {
		temp = temp->Next;
		len++;
	}
	return len;
}
//make an empty linked Stack,generate an empty header(length is 1)
Stack makeEmpty() {
	Stack ptrs;
	ptrs = (Stack)malloc(sizeof(struct SNode));
	ptrs->Next = NULL;
	return ptrs;
}
//check the linklist is empty
bool isEmpty(Stack ptrs) {
	if (length(ptrs) == 0) {
		return true;
	}
	else {
		return false;
	}
}
//push
Stack push(ElementType value, Stack ptrs) {
	Stack newLNode = (Stack)malloc(sizeof(struct SNode));
	newLNode->Data = value;
	newLNode->Next = ptrs->Next;
	ptrs->Next = newLNode;
	return ptrs;
}
//pop
ElementType pop(Stack ptrs) {
	if (isEmpty(ptrs)) {
		printf("the Stack has been empty.");
		return -1;
	}
	Stack temp = ptrs->Next;
	ElementType value = temp->Data;
	ptrs->Next = temp->Next;
	free(temp);
	return value;
}
//讀入並返回讀取幾個節點
int read() {
	int N = 0;
	scanf("%d\n", &N);
	Stack S = makeEmpty();
	//
	int preindex = 0;
	int inindex = 0;
	for (int i = 0; i < 2 * N; i++) {
		char operation[10];
		gets(operation);
		//如果讀取的操作(第二個字母是o),說明是pop,否則為push
		if (operation[1]=='o') {
			InOrderTraversal[inindex++] = pop(S);
		}
		else {
			int end = 0;
			while (operation[end] != '\0')end++;
			char dest[3] = {""};
			strncpy(dest, operation + 5, end-4);
			dest[2] = '\0';
			int num = atoi(dest);
			PreOrderTraversal[preindex++] = num;
			push(num, S);
		}
	}
	return N;
}
//left 和 right 分別為傳入樹的在中序遍歷的左右下標,root為當前樹的根
void getpost(Stack S,int left,int right,int root) {
	if (left > right) {
		return;
	}
	else {
		int index = left;
		while (index < right && InOrderTraversal[index] != PreOrderTraversal[root]) {
			index++;
		}
		push(PreOrderTraversal[root], S);
		getpost(S,index+1,right,root+1+index-left);
		getpost(S,left,index-1,root+1);
	}
}

int main() {
	/*
	* 分析題目可以看出,push的順序對應了先序遍歷,push和pop出的序列是中序
	* 所以題目無需建立樹,只需要通過先序和中序還原後序遍歷
	*/
	//讀取先序序列和中序序列
	int num = read();
	//根據先序序列和中序序列生成後序遍歷
	Stack PostOrderTraversal = makeEmpty();
	getpost(PostOrderTraversal, 0, num-1, 0);
	//列印後序遍歷
	bool isfirst = true;
	while (!isEmpty(PostOrderTraversal)) {
		if (isfirst) {
			printf("%d", pop(PostOrderTraversal));
			isfirst = false;
		}
		else {
			printf(" %d", pop(PostOrderTraversal));
		}
	}
}