二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性

基本子函数

1)树的节点定义

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第1张图片

2)创建二叉树

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第2张图片

3)二叉树的递归遍历

3.1 先序遍历(根->左子树->右子树)

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第3张图片

3.2 中序遍历(左子树->根->右子树)

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第4张图片

3.3 后序遍历(左子树->根->右子树)

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第5张图片

4)二叉树的非递归遍历(使用栈)

4.1 先序遍历(根->左子树->右子树)

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第6张图片

4.2 中序遍历(左子树->根->右子树)

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第7张图片

4.3 后序遍历(左子树->根->右子树)

这里的后序遍历需要注意,比先序和中序遍历稍微复杂一些,用一个比较巧妙的方法
我们其实希望栈顶至栈底依次为left, right, root,这样弹出的结果即为后序遍历
对于每个节点, 都入栈两次
在循环体中, 每次弹出一个节点赋给T, 如果T仍然等于栈的头结点,说明T的孩子们还没有被操作过,应该把它的孩子们加入栈中,否则, 访问T
也就是说, 第一次弹出, 将p的孩子压入栈中, 第二次弹出, 访问T
二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第8张图片

5)二叉树的结点总数

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第9张图片

6)二叉树的深度

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第10张图片

7)二叉树的叶子结点总数及其输出

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第11张图片
二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第12张图片

8)二叉树的层序遍历(使用队列,出队首,孩子进队尾)

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第13张图片

结果显示:

二叉树代码实现——创建、先序,中序和后序遍历(递归和非递归方式),层序遍历及有关的特性_第14张图片

测试代码

#pragma warning(disable:4996)
#include 
#include 
#include 
#include 
#include  
#include 

typedef char ElemType;
struct TNode {
	ElemType data;
	struct TNode *left;
	struct TNode *right;
};
typedef TNode * BinTree;


BinTree CreateBinTree() {
	BinTree T;
	ElemType ch;
	std::cin >> ch;

	if (ch == '-')     // 如果到了叶子节点, 接下来的左、右子树分别赋值为-
	{
		T = NULL;
	} else {
		T = (BinTree)malloc(sizeof(TNode));
		T->data = ch;
		T->left = CreateBinTree();   // 递归创建左子树
		T->right = CreateBinTree();  // 递归创建右子树
	}
	return T;
}

// 先序遍历
void PreOrderTraversal_(BinTree BT) {

	if (!BT) {
		printf("空树...\n");
		return;
	}

	std::stack<BinTree> sBT;
	BinTree T = BT;

	while (T || !sBT.empty()) {
		while (T) {
			printf("%c ",  T->data);
			sBT.push(T);
			T = T->left;
		}
		T = sBT.top();
		sBT.pop();
		T = T->right;
	}
	printf("\n");
}

// 中序遍历
void InOrderTraversal_(BinTree BT) {

	if (!BT) {
		printf("空树...\n");
		return;
	}

	std::stack<BinTree> sBT;
	BinTree T = BT;

	while (T || !sBT.empty()) {
		while (T) {
			sBT.push(T);
			T = T->left;
		}
		T = sBT.top();
		sBT.pop();
		printf("%c ",  T->data);
		T = T->right;
	}
	printf("\n");
}

// 后序遍历
void PostOrderTraversal_(BinTree BT) {

	if (!BT) {
		printf("空树...\n");
		return;
	}

	std::stack<BinTree> sBT;
	BinTree T = BT;
	// 我们其实希望栈顶至栈底依次为left,  right,  root, 这样弹出的结果即为后序遍历
	// 对于每个节点, 都入栈两次, 
	// 在循环体中, 每次弹出一个节点赋给T, 如果T仍然等于栈的头结点, 说明T的孩子们还没有被操作过, 应该把它的孩子们加入栈中, 
	// 否则, 访问T
	// 也就是说, 第一次弹出, 将p的孩子压入栈中, 第二次弹出, 访问T
	sBT.push(T);
	sBT.push(T);
	while (!sBT.empty()) {
		T = sBT.top();
		sBT.pop();
		if (!sBT.empty() && T == sBT.top()) {
			if (T->right) {
				sBT.push(T->right);
				sBT.push(T->right);
			}
			if (T->left) {
				sBT.push(T->left);
				sBT.push(T->left);
			}
		} else {
			printf("%c ",  T->data);
		}
	}
	
	printf("\n");
}

// 先序遍历(递归)
void PreOrderTraversal(BinTree BT) {
	if (BT) {
		printf("%c ", BT->data);
		PreOrderTraversal(BT->left);
		PreOrderTraversal(BT->right);
	}
}

// 中序遍历(递归)
void InOrderTraversal(BinTree BT) {
	if (BT) {
		InOrderTraversal(BT->left);
		printf("%c ", BT->data);
		InOrderTraversal(BT->right);
	}
}

// 后序遍历(递归)
void PostOrderTraversal(BinTree BT) {
	if (BT) {
		PostOrderTraversal(BT->left);
		PostOrderTraversal(BT->right);
		printf("%c ", BT->data);
	}
}

// 二叉树的结点数
int NumOfTNode(BinTree BT) {
	if (!BT) {
		return 0;
	} else {
		return 1 + NumOfTNode(BT->left) + NumOfTNode(BT->right);
	}
}

// 二叉树的深度
int DepthOfBinTree(BinTree BT) {
	if (BT) {
		return DepthOfBinTree(BT->left) > DepthOfBinTree(BT->right) ? DepthOfBinTree(BT->left) + 1 : DepthOfBinTree(BT->right) + 1;
	} else {
		return 0;
	}
}

// 二叉树的叶子结点数
int NumOfLeafNode(BinTree BT) {
	if (!BT) {
		return 0;
	} else if (BT->left == NULL && BT->right == NULL) {
		return 1;
	} else {
		return NumOfLeafNode(BT->left) + NumOfLeafNode(BT->right);
	}
}

// 输出叶子结点
void printLeafNode(BinTree BT) {
	if (BT) {
		if (BT->left == NULL && BT->right == NULL) {
			printf("%c ", BT->data);
		}
		printLeafNode(BT->left);
		printLeafNode(BT->right);
	}
}

void LevelOrderTraversal(BinTree BT) {
	if (!BT) {
		printf("空树...\n");
		return;
	}

	std::queue<BinTree> qBT;
	BinTree T = BT;

	qBT.push(T);
	while (!qBT.empty()) {
		T = qBT.front();
		qBT.pop();
		printf("%c ", T->data);
		if (T->left)
			qBT.push(T->left);
		if (T->right)
			qBT.push(T->right);
	}
	printf("\n");
}

int main(int argc,  char *argv[]) {
	// 创建一棵二叉树	
	BinTree T = CreateBinTree();
	printf("\n");

	printf("--------------------------二叉树的相关属性-------------------------- \n");
	printf("- 该二叉树的结点总数为   : %d\n", NumOfTNode(T));
	printf("- 该二叉树的深度为       : %d\n", DepthOfBinTree(T));
	printf("- 该二叉树的叶子结点数为 : %d\n", NumOfLeafNode(T));
	printf("- 该二叉树的叶子结点为 : ");
	printLeafNode(T);
	printf("\n");
	
	// 该树的先序遍历结果
	printf("【1】先序遍历: \n");
	printf("- 该树的非递归先序遍历结果为: ");
	PreOrderTraversal_(T);
	printf("- 该树的递归先序遍历结果为  : ");
	PreOrderTraversal(T);
	printf("\n\n");

	// 该树的中序遍历结果
	printf("【2】中序遍历: \n");
	printf("- 该树的非递归中序遍历结果为: ");
	InOrderTraversal_(T);
	printf("- 该树的递归中序遍历结果为  : ");
	InOrderTraversal(T);
	printf("\n\n");

	// 该树的后序遍历结果
	printf("【3】后序遍历: \n");
	printf("- 该树的非递归后序遍历结果为: ");
	PostOrderTraversal_(T);
	printf("- 该树的递归后序遍历结果为  : ");
	PostOrderTraversal(T);
	printf("\n\n");

	// 该树的层序遍历结果
	printf("【4】层序遍历: \n");
	printf("- 该树的层序遍历结果为: ");
	LevelOrderTraversal(T);
	printf("\n\n");


	return 0;
}

你可能感兴趣的:(数据结构)