链式二叉树的创建及递归与非递归遍历的实现

文章目录

  • [1. 数据元素的表示](#1. 数据元素的表示)
  • [2. 创建二叉树](#2. 创建二叉树)
  • [3. 遍历二叉树](#3. 遍历二叉树)
    • [3.1 先序遍历](#3.1 先序遍历)
      • [3.1.1 递归遍历](#3.1.1 递归遍历)
      • [3.1.2 非递归遍历](#3.1.2 非递归遍历)
    • [3.2 中序遍历](#3.2 中序遍历)
      • [3.2.1 递归遍历](#3.2.1 递归遍历)
      • [3.2.2 非递归遍历](#3.2.2 非递归遍历)
    • [3.3 后序遍历](#3.3 后序遍历)
      • [3.3.1 递归遍历](#3.3.1 递归遍历)
      • [3.3.2 非递归遍历](#3.3.2 非递归遍历)
    • [3.4 层次遍历](#3.4 层次遍历)

1. 数据元素的表示

c 复制代码
#define ElemType char		// 树结点的数据元素类型

typedef struct BiTNode{	// 链式二叉树
	ElemType data;		// 数据域
	struct BiTNode* lchild;	// 左孩子指针
	struct BiTNode* rchild;	// 右孩子指针
}BiTNode,*BiTree;

2. 创建二叉树

c 复制代码
/* 基于先序遍历递归创建二叉树 */
BiTree PreOrderCreate(BiTree &T) {
	ElemType data;
	printf("输入当前结点的值:");
	scanf("%c", &data);
	getchar();

	if (data!='#') {	// data不为'#',表示要创建新结点
		BiTNode* t = (BiTNode*)malloc(sizeof(BiTNode));	// 创建新结点
		if (!t) {	// 创建结点失败,返回空指针
			return NULL;
		}

		t->data = data;
		t->lchild = t->rchild = NULL;		// 将新结点的左、右孩子指针置为空
		T = t;

		T->lchild = PreOrderCreate(T->lchild);	// 递归创建左子树
		T->rchild = PreOrderCreate(T->rchild);	// 递归创建右子树
	}

	return T;
}

3. 遍历二叉树

3.1 先序遍历

3.1.1 递归遍历

c 复制代码
/* 先序遍历(NLR) */
void PreOrder(BiTree T) {
	if (T) {
		Visit(T);					// 访问根结点
		PreOrder(T->lchild); 		// 递归遍历左子树
		PreOrder(T->rchild);		// 递归遍历右子树
	}
}

3.1.2 非递归遍历

c 复制代码
/* 先序遍历(LNR)非递归 */
void PreOrder(BiTree T) {
	LinkStack S;	// 定义一个链栈
	InitStack(S);	// 初始化链栈

	BiTree p = T;	// p是遍历指针
	while(p||!StackEmpty(S)){	// 进行遍历,p指针与栈同时为空,结束遍历
		if(p){				// 子树的根结点非空
            Visit(p);		// 访问子树的根结点
			Push(S,p);		// 当前结点入栈
			p=p->lchild;	// 一直向左走
		}
		else{				// 子树的根结点为空,出栈并转向栈结点的右子树
			Pop(S,p);		// 栈顶元素出栈(子树的根结点)
			p=p->rchild;	// 向子树根结点的右子树走
		}
	}
}

3.2 中序遍历

3.2.1 递归遍历

c 复制代码
/* 中序遍历(LNR) */
void InOrder(BiTree T) {
	if (T) {
		PreOrder(T->lchild);		// 递归遍历左子树
		Visit(T);					// 访问根结点
		PreOrder(T->rchild);		// 递归遍历右子树
	}
}

3.2.2 非递归遍历

c 复制代码
/* 中序遍历(LNR)非递归 */
void InOrder(BiTree T) {
	LinkStack S;	// 定义一个链栈
	InitStack(S);	// 初始化链栈

	BiTree p = T;	// p是遍历指针
	while(p||!StackEmpty(S)){	// p非空或栈非空循环
		if(p){				// 子树的根结点非空
			Push(S,p);		// 当前结点入栈
			p=p->lchild;	// 一直向左走
		}
		else{				// 子树的根结点为空,出栈并转向栈结点的右子树
			Pop(S,p);		// 栈顶元素出栈(子树的根结点)
			Visit(p);		// 访问子树的根结点
			p=p->rchild;	// 向子树根结点的右子树走
		}
	}
}

3.3 后序遍历

3.3.1 递归遍历

c 复制代码
/* 后序遍历(LRN) */
void PostOrder(BiTree T) {
	if (T) {
		PreOrder(T->lchild);		// 递归遍历左子树
		PreOrder(T->rchild);		// 递归遍历右子树
		Visit(T);					// 访问根结点
	}
}

3.3.2 非递归遍历

c 复制代码
/* 后序遍历(LRN) 非递归*/
void PostOrder(BiTree T){
	LinkStack S;	// 创建链栈
	InitStack(S);	// 初始化链栈

	BiTNode *p=T;		// 遍历结点指针
	BiTNode *r=NULL;	// 记录上一次访问的结点

	while(p||!StackEmpty(S)){	// 遍历树,p指针与链栈同时为空遍历结束
		if(p){		// 走到最左边
			Push(S,p);	
			p=p->lchild;
		}
		else{	// 向右
			GetTop(S,p);	// 读栈顶元素结点(非出栈)
			if(p->rchild&&p->rchild!=r){	// 若右子树存在,且未被访问过
				p=p->rchild;	// 转向右
			}else{	// 否则,弹出结点并访问
				Pop(S,p);		// 将结点弹出
				Visit(p);		// 访问该结点
				r=p;			// 记录上一次访问的结点
				p=NULL;			// 结点访问完后,重置p指针
			}
		} 
	}
}

3.4 层次遍历

c 复制代码
/* 层次遍历 */
void LevelOrder(BiTree T) {
    
	LinkQueue Q;	// 定义一个链队列
	InitQueue(Q);	// 初始化队列

	EnQueue(Q,T);		// 根结点入队
	BiTNode *p;			// 遍历结点指针
	
	while(!(QueueEmpty(Q))){	// 进行遍历,队列为空遍历结束
			DeQueue(Q,p);	// 队头元素出队
			Visit(p);		// 访问该结点

			if(p->lchild){	// 该结点存在左子树(左孩子),进队
				EnQueue(Q,p->lchild);
			}

			if(p->rchild){	// 该结点存在右子树(右孩子),进队
				EnQueue(Q,p->rchild);
			}
	}
}

.

相关推荐
小字节,大梦想31 分钟前
【C++】二叉搜索树
数据结构·c++
Cons.W1 小时前
Codeforces Round 975 (Div. 1) C. Tree Pruning
c语言·开发语言·剪枝
我是哈哈hh1 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
挥剑决浮云 -1 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记
丶Darling.1 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5202 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
Indigo_code2 小时前
【数据结构】【链表代码】合并有序链表
数据结构·windows·链表
jiyisuifeng19912 小时前
代码随想录训练营第54天|单调栈+双指针
数据结构·算法
一颗星星辰2 小时前
C语言 | 第十章 | 函数 作用域
c语言·开发语言