王道数据结构伪代码实现——第五章 树与二叉树

目录

5.3.1 二叉树的遍历

1.function.h

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

typedef char BiElemType;

//二叉树结点的结构体定义
typedef struct BiTNode {
	BiElemType c;//c就是书上的data
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode, * BiTree;

//辅助队列结点的结构体定义
typedef struct tag {
	BiTree p;//树的某一个结点的地址值
	struct tag* pnext;
}tag_t, * ptag_t;

//栈的相关数据结构
#define MaxSize 50
typedef BiTree ElemType;
typedef struct {
	ElemType data[MaxSize];
	int top;
}SqStack;
//声明放在头文件中的目的:声明一次即可,在其他文件中要引用函数时,#include 头文件即可,不用多次声明
void InitStack(SqStack& S);
bool StackEmpty(SqStack& S);
bool Push(SqStack& S, ElemType x);
bool Pop(SqStack& S, ElemType& x);
bool GetTop(SqStack& S, ElemType& x);

//队列的相关数据结构(链队)
typedef struct LinkNode {
	ElemType data;
	struct LinkNode* next;
}LinkNode;

//单独定义队头、队尾的指针
typedef struct {
	LinkNode* front, * rear;
}LinkQueue;

void InitQueue(LinkQueue& Q);
bool IsEmpty(LinkQueue Q);
void EnQueue(LinkQueue& Q, ElemType x);
bool DeQueue(LinkQueue& Q, ElemType& x);

2. main.cpp

#include "function.h"
#define _CRT_SECURE_NO_WARNINGS

//递归实现
//abdhiejcfg
void preOrder(BiTree p)
{
	if (p != NULL)
	{
		putchar(p->c);//等价于visit函数
		preOrder(p->lchild);
		preOrder(p->rchild);
	}
}

//中序遍历  hdibjeafcg
void InOrder(BiTree p)
{
	if (p != NULL)
	{
		InOrder(p->lchild);
		putchar(p->c);
		InOrder(p->rchild);
	}
}
//hidjebfgca

void PostOrder(BiTree p)
{
	if (p != NULL)
	{
		PostOrder(p->lchild);
		PostOrder(p->rchild);
		putchar(p->c);
	}
}

//中序遍历非递归,非递归执行效率更高,考的概率很低
void InOrder2(BiTree T)
{
	SqStack S;
	InitStack(S); BiTree p = T;//p是遍历指针
	while (p || !StackEmpty(S))//p非空或者栈非空
	{
		if (p)
		{
			Push(S, p);
			p = p->lchild;//一路向左,找到最左结点
		}
		else {//找到最左结点后,接着要依次访问其父结点及其右兄弟(中序遍历)
			Pop(S, p); putchar(p->c);//putchar(p->c)相当于visit(p)函数
			p = p->rchild;
		}
	}
}

//层次遍历,广度优先遍历
void LevelOrder(BiTree T)
{
	LinkQueue Q;
	InitQueue(Q);

	BiTree p = T;
	EnQueue(Q, T);//树根入队
	while (!IsEmpty(Q))
	{
		DeQueue(Q, p);
		putchar(p->c);
		if (p->lchild != NULL)
			EnQueue(Q, p->lchild);
		if (p->rchild != NULL)
			EnQueue(Q, p->rchild);
	}
}

//层序建树——借助逻辑上的辅助队列
int main() {
	BiTree tree = NULL;//树的根结点
	BiTree tpnew;//指向树的新结点的指针
	ptag_t phead = NULL, ptail = NULL,listpnew = NULL, pcur = NULL;
	char c;
	//辅助队列中的队头,队尾结点,指向新结点的listpnew,指向当前插入位置的父结点的pcur
	//abcdefg
	while (scanf_s("%c", &c) != EOF) {
		if ('\n' == c) {
			break;//结束循环
		}
		//分配空间
		tpnew = (BiTree)calloc(1, sizeof(BiTNode));//给树结点分配空间
		tpnew->c = c;//输入的元素放入树结点中
		listpnew = (ptag_t)calloc(1, sizeof(tag_t));//给队列结点分配空间
		listpnew->p = tpnew;//树的结点地址放入队列结点中
		if (NULL == tree) {
			tree = tpnew;
			phead = listpnew;
			ptail = listpnew;
			pcur = listpnew;//pcur始终指向插入位置的父结点
			continue;//继续下一轮循环
		}
		else {
			ptail->pnext = listpnew;
			ptail = listpnew;//队列中使用尾插法
		}
		if (NULL == pcur->p->lchild) {//通过队列找到树中结点
			pcur->p->lchild = tpnew;
		}
		else if (NULL == pcur->p->rchild) {
			pcur->p->rchild = tpnew;
			pcur = pcur->pnext;//以a为根节点的左右子树已经插好,逻辑上需要将a出队,插入位置的父节点由a变为了b,所以pcur要后移
		}

	}
	InOrder(tree);
	printf("\n");
	PostOrder(tree);
	printf("\n");
	LevelOrder(tree);
}

3. stack.cpp

#include "fun.h"


void InitStack(SqStack& S)
{
	S.top = -1;
}

bool StackEmpty(SqStack& S)
{
	if (S.top == -1)
		return true;
	else
		return false;
}
//入栈
bool Push(SqStack& S, ElemType x)
{
	if (S.top == MaxSize - 1)
	{
		return false;
	}
	S.data[++S.top] = x;
	return true;
}
//出栈
bool Pop(SqStack& S, ElemType& x)
{
	if (-1 == S.top)
		return false;
	x = S.data[S.top--];
	return true;
}
//读取栈顶元素
bool GetTop(SqStack& S, ElemType& x)
{
	if (-1 == S.top)
		return false;
	x = S.data[S.top];
	return true;
}

4. queue.cpp

#include "fun.h"
//带头结点的链队——头结点的下一个节点才有数据
//初始化
void InitQueue(LinkQueue& Q)
{
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
	Q.front->next = NULL;
}

//判空
bool IsEmpty(LinkQueue Q)
{
	if (Q.front == Q.rear)
		return true;
	else
		return false;
}

//入队、出队操作当作链表处理
//入队——尾插法
void EnQueue(LinkQueue& Q, ElemType x)
{
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x; s->next = NULL;
	Q.rear->next = s;
	Q.rear = s;
}

//出队——头部删除法
bool DeQueue(LinkQueue& Q, ElemType& x)
{
	if (Q.front == Q.rear) return false;//队空不出
	LinkNode* p = Q.front->next;//头结点什么都没存,所以头结点的下一个节点才有数据(带头结点的链队)
	x = p->data;
	Q.front->next = p->next;
	if (Q.rear == p)
		Q.rear = Q.front;
	free(p);
	return true;
}

5.3.2 线索二叉树

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

typedef char ElemType;
typedef struct ThreadNode {
	ElemType data;
	struct ThreadNode* lchild, * rchild;
	int ltag, rtag;
}ThreadNode, * ThreadTree;
//手工建线索树,总计5个结点
void BulidThreadTree(ThreadTree& T)
{
	ThreadTree arr[5];
	int i;
	for (i = 0; i < 5; i++)
	{
		arr[i] = (ThreadTree)malloc(sizeof(ThreadNode));
		memset(arr[i], 0, sizeof(ThreadNode));
		arr[i]->data = 'A' + i;
	}
	arr[0]->lchild = arr[1];
	arr[0]->rchild = arr[2];
	arr[1]->rchild = arr[3];
	arr[2]->lchild = arr[4];
	T = arr[0];
}

void InThread(ThreadTree& p, ThreadTree& pre)
{
	if (p != NULL) {
		InThread(p->lchild, pre);//递归找树的左孩子
		if (p->lchild == NULL) {//左边为NULL,填写当前结点的前驱
			p->lchild = pre;
			p->ltag = 1;
		}
		if (pre != NULL && pre->rchild == NULL) {
			//pre节点右孩子为NULL,就让其指向后继节点,而后继结点刚好就是p
			pre->rchild = p;
			pre->rtag = 1;
		}
		pre = p;
		InThread(p->rchild, pre);
	}
}

void CreateInThread(ThreadTree T)
{
	ThreadTree pre = NULL;//使用辅助指针pre
	if (T != NULL) {
		InThread(T, pre);
		pre->rchild = NULL;
		pre->rtag = 1;
	}
}

//求中序序列下的第一个结点
ThreadNode* Firstnode(ThreadNode* p)
{
	while (p->ltag == 0)
		p = p->lchild;
	return p;
}
//p在中序序列下的后继结点

int main()
{
	ThreadTree T;
	ThreadTree p;
	BulidThreadTree(T);
	CreateInThread(T);//构建线索二叉树
	p = Firstnode(T);
	printf("最左下结点值为 %c\n", p->data);
	
}

5.5.1 二叉排序树

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

typedef int KeyType;//关键字类型

//BST结点定义
typedef struct BSTNode {
	KeyType key;
	struct BSTNode* lchild, * rchild;
}BSTNode, *BiTree;

//插入
int BST_Insert(BiTree& T, KeyType k) {
	if (NULL == T) {
		T = (BiTree)malloc(sizeof(BSTNode));
		T->key = k;
		T->lchild = T->rchild = NULL;
		return 1;
	}
	else if (k == T->key) {
		return 0;
	}
	else if (k < T->key) {
		return  BST_Insert(T->lchild, k);
	}
	else {
		return  BST_Insert(T->rchild, k);
	}
}

//构造BST
void Creat_BST(BiTree& T, KeyType str[], int n) {//str[]为关键字序列,n为关键字个数
	T = NULL;//初始时T为空树
	int i = 0;//关键字序列的下标,用来取关键字插入到BST中
	while (i < n) {//依次将每个关键字插入到BST中
		BST_Insert(T, str[i]);
		i++;
	}
}

//查找(非递归)
BSTNode* BST_Search(BiTree T, KeyType k, BiTree& p) {
	p == NULL;
	while (T != NULL && T->key != k) {
		if (k < T->key) {
			T = T->lchild;
			p = T;
		}
		else {
			T = T->rchild;
			p = T;
		}
	}
	return T;
}

//删除
void DeleteNode(BiTree& root, KeyType x) {
	if (NULL == root) {
		return;
	}
	if (x < root->key) {
		DeleteNode(root->lchild, x);
	}
	if (x > root->key) {
		DeleteNode(root->rchild, x);
	}
	else {
		if (NULL == root->lchild) {
			BiTree TNode = root;
			root = root->rchild;
			free(TNode);
		}
		else if (NULL == root->rchild) {
			BiTree TNode = root;
			root = root->lchild;
			free(TNode);
		}
		else {
			BiTree TNode = root->lchild;
			if (TNode->lchild != NULL) {
				TNode = TNode->rchild;
			}
			root->key = TNode->key;
			DeleteNode(root->lchild, TNode->key);
		}
	}
}

//中序遍历
void InOrder(BiTree T) {
	if (T != NULL) {
		InOrder(T->lchild);
		printf("%3d", T->key);
		InOrder(T->rchild);
	}
}

int main()
{
	BiTree T;
	BiTree parent;//存储父亲结点的地址值
	BiTree search;
	KeyType str[] = { 54,20,66,40,28,79,58 };//将要进入二叉排序树的元素值
	Creat_BST(T, str, 7);
	InOrder(T);
	printf("\n");
	search = BST_Search(T, 40, parent);
	if (search)
	{
		printf("找到对应结点,值=%d\n", search->key);
	}
	else {
		printf("未找到对应结点\n");
	}
	DeleteNode(T, 66);
	InOrder(T);
	printf("\n");
}

上一篇:2020.11.11问题 B: DS二叉树--同一棵二叉树?


下一篇:二叉树的基本应用(PTA题型为例)