數據結構第三節(樹(上))

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

兩種查找方式順序查找和二分查找

順序查找(哨兵法)

對於一個線性表方便的查找方式是,從後向前查找且將被查找的值放在最前面做爲哨兵,只須要判斷下標位置的元素是否爲查找元素,而不用考慮下標是否走到邊界(由於邊界元素正好是咱們的哨兵,走到了這裏自動退出)算法

代碼實現:數組

#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,同理....post

代碼實現:ui

#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時爲空樹。this

非空樹的性質

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

樹的一些基本術語

1.結點的度(Degree):結點的子樹個數
2.樹的度:樹的全部結點中最大的度數
3.葉結點(Leaf):度爲0的結點
4.父結點(Parent):有子樹的結點是其子樹的根結點的父結點
5.子結點(Child):若A結點是B結點的父結點,則稱B結點是A結點的子結點;子結點也稱孩子結點。
6.兄弟結點(Sibling):具備同一父結點的各結點彼此是兄弟結點。
7.路徑和路徑長度:從結點\(n_1\)\(n_k\)的路徑爲一個結點序列\(n_1\) , \(n_2\),… , \(n_k\), \(n_i\)\(n_{i+1}\)的父結點。路徑所包含邊的個數爲路徑的長度。
9.祖先結點(Ancestor):沿樹根到某一結點路徑上的全部結點都是這個結點的祖先結點。
10.子孫結點(Descendant):某一結點的子樹中的全部結點是這個結點的子孫。
11.結點的層次(Level):規定根結點在1層,其它任一結點的層數是其父結點的層數加1。
12.樹的深度(Depth):樹中全部結點中的最大層次是這棵樹的深度。3d

二叉樹(一種特殊的樹)

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

三種特殊的二叉樹

二叉樹的性質

1.第i層最多有\(2^{i-1}\)個節點
2.深度爲k的樹最多有\(2_k-1\)個節點
3.對於一個非空二叉樹用\(n\)k(k \(\in\) 0,1,2)表示有幾個兒子的節點。有等式\(n_0\) = \(n_2\) + 1 恆成立。
證: 樹的總邊數 = \(n_0\) + \(n_1\) + \(n_2\) - 1(除了根節點外每一個節點都有父節點)
樹的總邊數 = 0 * \(n_0\) + 1 * \(n_1\) + 2 * \(n_2\)(節點的下標表明瞭他有幾個兒子也就是幾條邊)
聯立可得\(n_0\) = \(n_2\) + 1

二叉樹的實現

若是採用線性的儲存方法,保存在數組中,根據上面的二分查找咱們能夠知道,二分查找順序固定,能夠行的通,但對於不是完美二叉樹,會在空間上形成浪費,並不推薦。
經常使用的作法是採用鏈式儲存下面給出樹節點代碼實現

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

二叉樹的遍歷

對於一顆二叉樹,咱們常常但願訪問樹中的每個結點而且查看它的值。有不少常見的順序來訪問全部的結點,並且每一種都有有用的性質。
這裏介紹基於深度的前序中序後序遍歷
對一棵樹前序遍歷,就是先訪問它的根節點,再訪問他的左子樹,再訪問他的右子樹。
對一棵樹中序遍歷,就是先訪問他的左子樹,再訪問它的根節點,再訪問他的右子樹。
對一棵樹後序遍歷,就是先訪問他的左子樹,再訪問他的右子樹,再訪問它的根節點。

不難看出這三種遍歷方式均可以用遞歸來實現,下面給出代碼實現

#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次掏出,後續第三次拋出,根據這種特性咱們能夠經過堆棧來實現。

#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;
		}
	}
}

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

代碼實現:

#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就不是同構的。
12

現給定兩棵樹,請你判斷它們是不是同構的。
輸入格式:
輸入給出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

代碼實現:

#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:

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

Sample Output:

4 1 5

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

#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的順序對應了中序遍歷,因此對於該題的解法爲,先將前序遍歷順序和中序遍歷順序保存在數組中,再根據前序遍歷和中序遍歷推導出後序遍歷。由於後序遍歷爲左右根,因此能夠採用堆棧的方法的,先將樹的根堆入,再堆入右子樹,再堆入左子樹,遞歸完成。

代碼實現:

#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));
		}
	}
}
相關文章
相關標籤/搜索