数据结构与算法——二叉树的c++实现

线索二叉树:前驱和后继需要看遍历出来的序列才能决定是谁。

 

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>

using namespace std;


#define MAX_SIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2


// 二叉链表结构定义
typedef struct BiNode
{
	int data;  // 存放数据
	struct BiNode* lchild, * rchild;   // 左右孩子指针
}BiNode, *BiTree;   //前面是普通节点类型,也就是一个结构体而已;后面是结构体指针,指向这个节点;

// 三叉链表结构定义
typedef struct TriTNode
{
	int data;
	struct TriTNode* lchild, * parent, * rchild;  // 增加指向双亲结点的指针域
}TriTNode, *TriTree;


// 递归遍历算法:
// 二叉树先序遍历算法:这里递归一层一层深入,找到最后的叶子结点,就一层一层退出,直到根节点那层都执行完才会进入主程序
int PreOrderTraverse(BiTree T)  // 等价于 *BiNode T
{
	if (T == nullptr)
	{
		return FALSE;
	}
	else
	{
		cout << "节点元素为:" << T->data << endl;   // 访问根结点
		PreOrderTraverse(T->lchild);  // 递归遍历左子树
		PreOrderTraverse(T->rchild);  // 递归遍历右子树
	}
}

// 二叉树中序遍历:
int InOrderTraverse(BiTree T)
{
	if (T == nullptr)
	{
		return FALSE;
	}
	else
	{
		PreOrderTraverse(T->lchild);  // 递归遍历左子树
		cout << "节点元素为:" << T->data << endl;   // 访问根结点 - 输出元素
		PreOrderTraverse(T->rchild);  // 递归遍历右子树
	}
}

// 二叉树后序遍历
int PostOrderTraverse(BiTree T)
{
	if (T == nullptr)
	{
		return FALSE;
	}
	else
	{
		PreOrderTraverse(T->lchild);  // 递归遍历左子树
		PreOrderTraverse(T->rchild);  // 递归遍历右子树
		cout << "节点元素为:" << T->data << endl;   // 访问根结点 - 输出元素
	}
}


// 非递归算法
// 中序非递归遍历算法:先存储的不能访问,后存储的先访问 ——> 栈
// 基本思想:(1)建立一个栈;(2)根结点进栈,遍历左子树;(3)根结点出栈,输出根节点,访问右子树;

// 用顺序栈存储:栈的定义
typedef struct SqStack
{
	int* base;  // 栈底指针
	int* top;  // 栈顶指针 —— 在栈顶元素的上一个位置
	int stacksize;  // 栈的空间
};

// 初始化
bool InitStack(SqStack& S)
{
	S.base = new int[MAX_SIZE];  // 在堆区开辟空间;并将栈底指针指向
	if (!S.base) exit(OVERFLOW);
	S.top = S.base;  // 使栈顶指针等于栈底指针
	S.stacksize = MAX_SIZE;
	return true;
}

// 判断是否为空
bool IsEmpty(SqStack S)
{
	if (S.base == S.top)
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool PushStack(SqStack& S, int e)
{
	if ((S.top - S.base) == S.stacksize)  // 判断栈满
	{
		cout << "栈满了!!" << endl;
		return false;
	}
	else
	{
		// 等价于 *(S.top)++ = e;
		*(S.top) = e;  // 将 S.top 指针指向的位置赋值为 e
		(S.top)++;
		return true;
	}
}

// 顺序栈的出栈:
/*
	流程:(1)判断是否栈空,若空了则报错(下溢)
		  (2)获取栈顶元素 e
		  (3)栈顶指针减一
*/
bool PopStack(SqStack& S, int& e)
{
	if (S.base == S.top)  // 等价于 if(IsEmpty(S))
	{
		cout << "栈已经空了!!" << endl;
		return false;
	}
	--(S.top);  // 先将 top 指针下移
	e = *(S.top); // 再将 top 指针指向的位置的值赋给 e 带回
	return true;
}


int InOrderStackTraverse(BiTree T)
{
	BiTree p, q; // 创建两个指针
	SqStack S;  // 创建一个栈 S
	InitStack(S);   // 初始化栈
	p = T;   // 让指针 p 指向 指针 T所指向的地址

	// p 访问子树根结点;不为空则继续执行 if(p) 语句,表示将根节点入栈S并移到左子树;若为空执行 else 语句,然后出栈并输出根节点;
	while (p || !IsEmpty(S))  
	{
		if (p) {
			PushStack(S, p->data); // 将 p 指向结点的元素入栈 
			q = p;
			p = p->lchild;    // p 继续去左子树
		}
		else
		{
			int e;
			PopStack(S, e);  // 根节点出栈
			cout << "元素值为:" << e << endl;
			p = q->rchild;  // p 通过指向根节点处的指针 q 去到右子树了;这里永远需要 另一个指针指向 p 的上一个子树的根节点,否则p去不到右子树了
		}
	}
	return OK;
}


// 先序遍历创造二叉树:链表形式
int CreateBiTree(BiTree& T)
{
	char ch;
	cout << "请输入二叉树结点的数据" << endl;
	cin >> ch;
	if (ch == '#')
	{
		T = nullptr;
	}
	else
	{
		T = new BiNode;  // 创造新结点 - 向计算机内存申请空间给新结点,成功就继续,不成功退出。并且分配的空间给T,即由指针T指向这块空间
		if (!T)
		{
			exit(OVERFLOW);
		}
		else
		{
			T->data = ch;   // 根结点 或者 每个小树的根节点 - T指针指向的这块空间的结点的值域为 输入值 ch;
			CreateBiTree(T->lchild);   // 递归,每个树结构走完左子树才能一层层退出,再执行右子树
			CreateBiTree(T->rchild);   // 
		}
	}
	return OK;
}

// 复制二叉树:先序遍历:
// 1. 如果是空树,递归结束 -> 2. 否则申请新结点空间,复制根结点 
// 2.1 递归复制左子树   2.2 递归复制右子树 
int Copy(BiTree T, BiTree& NewT)
{
	if (T == nullptr)
	{
		NewT = nullptr;
		return 0;
	}
	else
	{
		NewT = new BiNode;  // 向内存申请空间用来开辟一个新结点,并用指针NewT指向新结点所在的空间
		NewT->data = T->data;  // 通过指针NewT指向的新结点,从而让新结点值域改为 T的值域
		Copy(T->lchild, NewT->lchild);   // T和NewT都要走向同一个结点处。
		Copy(T->rchild, NewT->rchild);
	}
	return OK;
}

// 计算二叉树深度 - 递归
// 1. 如果是空树,则深度为0 -> 2. 否则,递归计算左子树深度记为m,递归计算右子树深度为n,比较m和n,大者最后再加1
int Depth(BiTree T)
{
	if (T == nullptr)
	{
		cout << "树为空!" << endl;
		return 0;
	}
	else   // 这里要理解:记住一层层返回(递归的思想),即最后一个小树计算完把比较的数据传给上级树,一层一层回传
	{
		int m = Depth(T->lchild);
		int n = Depth(T->rchild);
		if (m > n)
		{
			return m + 1;
		}
		else
		{
			return n + 1;
		}
	}
}

// 计算二叉树总个数:
// 1. 如果是空树,则结点总个数为0 -> 2.否则,结点个数就是 左子树结点个数 + 右子树结点个数 + 1
int NodeCount(BiTree T)
{
	if (T == nullptr)
	{
		return 0;
	}
	else
	{
		int L = NodeCount(T->lchild);
		int R = NodeCount(T->rchild);
		return L + R + 1;
		//return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
	}
}

// 计算二叉树叶子结点树
// 1. 如果是空树,则叶子结点总个数为0 -> 2.否则,结点个数就是 左子树叶子结点个数 + 右子树叶子结点个数
int LeafNodeCount(BiTree T)
{
	if (T == nullptr)
	{
		return 0;
	}
	if (T->lchild == nullptr && T->rchild == nullptr)
	{
		return 1;
	}
	else
	{
		return LeafNodeCount(T->lchild) + LeafNodeCount(T->rchild);
	}
}


int main()
{
	BiTree T;
	BiTree NewT;
	CreateBiTree(T);
	Copy(T, NewT);

	cout << "先序遍历二叉树NewT,结点元素为:" << endl;
	PreOrderTraverse(NewT);

	cout << "中序遍历二叉树NewT,结点元素为:" << endl;
	InOrderTraverse(NewT);

	cout << "后序遍历二叉树NewT,结点元素为:" << endl;
	PostOrderTraverse(NewT);

	cout << "二叉树深度为:" << Depth(NewT) << endl;
	cout << "二叉树总结点为" << NodeCount(NewT) << endl;
	cout << "二叉树叶子节点为:" << LeafNodeCount(NewT) << endl;

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值