数据结构与算法基础(王卓)(19):遍历二叉树算法的实现

目录

二叉链表、三叉链表定义:

遍历二叉树具体实操:

最终结果:

遍历的实现:

递归遍历程序实现:

三种遍历算法的代码模块

为了文档的简洁性,避免赘述,我们这里只写先序遍历的算法:(中序后序调换语句顺序即可)

非递归遍历程序算法实现:

前置条件(二叉树和顺序栈的):

递归遍历程序算法实现:

以中序遍历为例:

思路:

ISSUES:

不构造新变量的最终程序成品:

构造新变量的最终程序成品:(标准答案)

二叉树层次遍历算法:

核心思路:

前置条件:(原创版本)

函数实现:(原创)

ISSUES:


二叉链表、三叉链表定义:

#include<iostream>
using namespace std;

typedef int Status;
#define MAXTSIZE 100

typedef char TElemtype;//Tree Elemtype
//根据需求情况修改
typedef TElemtype SqBiTree;//sequence binary tree
//binary:二进制的; 二元的; 由两部分组成的;
SqBiTree bt;//binary tree

struct BiNode//二叉链表存储结构
{
	TElemtype data;
	struct
		BiNode* lchild, * rchild;
	//左右孩子指针
};
typedef BiNode * BiTree;

struct TriNode//trinary:三元的
{
	TElemtype data;
	struct
		BiNode* lchild, * rchild,* parent;
};
typedef TriNode* TriTree;

int main()
{

}

遍历二叉树具体实操:

最终结果:

遍历的实现:

递归遍历程序实现:

三种遍历算法的代码模块

为了文档的简洁性,避免赘述,我们这里只写先序遍历的算法:(中序后序调换语句顺序即可)

void Pre(BiTree& T)
{
	if (T != NULL) 
	{
		cout << T->data;
		//printf("%d\t{,T->data);
		Pre(T->lchild);
		Pre(T->rchild);
	}
}

//注意Pre函数必须要写在遍历函数前面

Status PreOrderTraverse(BiTree T)
{
	if (T == NULL)
		return 0;//空二叉树
	else
	{
		Pre(T);
		//visit(T);//访问根结点
		PreOrderTraverse(T->lchild);//递归遍历左子树
		PreOrderTraverse(T->rchild); //递归遍历右子树
	}
}

注:

//PPT上写的是
//void Pre(BiTree* T)
//但是我们的BiTree已经是一个指针类型,所以没必要再画蛇添足

这里:
void Pre(BiTree& T)

void Pre(BiTree T)

都可以


递归遍历程序算法实现:

前置条件(二叉树和顺序栈的):

//顺序栈
#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit
#include<math.h>//OVERFLOW,exit

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

#define MAXlength 100  
//可按需修改,PPT中写的是MAXlength

typedef int Status;
typedef char  SElemType; 
typedef char TElemtype;//根据需求情况修改

struct SqStack
{
	SElemType* base; //栈底指针  
	SElemType* top;//栈顶指针
	int stacksize; //栈可用最大容量
};

//二叉树
#define MAXTSIZE 100

typedef TElemtype SqBiTree;//sequence binary tree
//binary:二进制的; 二元的; 由两部分组成的;
SqBiTree bt;//binary tree

struct BiNode//二叉链表存储结构
{
	TElemtype data;
	struct
		BiNode* lchild, * rchild;
	//左右孩子指针
};
typedef BiNode* BiTree;

//函数
Status InitStack(SqStack& S)//构造一个空栈
{
	S.base = new SElemType[MAXlength];
	//或
	//S.base = (SElemType*)malloc(MAXlength * sizeof(SElemType));
	if (!S.base) exit(OVERFLOW);// 存储分配失败
	S.top = S.base;
	//栈顶指针等于栈底指针
	S.stacksize = MAXlength;
	return true;
}

Status StackEmpty(SqStack S)
{
	// 若栈为空,返回TRUE;否则返回FALSE 
	if (S.top == S.base)
		return TRUE;
	else
		return FALSE;
}

int StackLength(SqStack S)
{
	return S.top - S.base;
}

Status ClearStack(SqStack S)//清空顺序栈
{
	if (S.base)
		S.top = S.base;
	return OK;
}

Status DestroyStack(SqStack& S)//销毁
{
	if (S.base)
	{
		delete S.base;
		S.stacksize = 0;
		S.base = S.top = NULL;
	}
	return OK;
}

Status Push(SqStack& S, SElemType e)
{
	if (S.top - S.base == S.stacksize)
		//不是MAXlength
		return OVERFLOW;
	*S.top = e;
	S.top++;
	//也可以写成:
	//*S.top++ = e;
	return true;
}

Status Pop(SqStack& S, SElemType& e)
//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;	否则返回ERROR
{
	if (S.top == S.base) // 等价于 if(StackEmpty(S))
		return UNDERFLOW;//ERROR;
	e = *S.top;
	S.top--;
	//e = *--S.top;
	return true;
}

递归遍历程序算法实现:

以中序遍历为例:

思路:

有(根)结点:

  1. 把根结点存到栈里
  2. 访问(指针指向)左子树
  3. 输出左子树(后面想了想又觉得不对,如果这样的话无论如何第一个输出的都是第二层的左孩子)

(根)结点为空:

  1. 输出上一层的根结点(位于栈顶)
  2. 指针指向根结点的右子树

Project 1:

Status InOrderTraverse(BiTree T)
{
	BiTree p=T;//用于访问结点的指针
	SqStack S;
	InitStack(S);
	if (p)//p不为空,有(根)结点
		//另外这里注意,我们无法构造定义出“空结点/空树”,不要浪费力气了
	{
		Push(S, p->data);//		把根结点存到栈里
		p->lchild;//		访问(指针指向)左子树
	}
	else//(根)结点为空
	{
		Pop(S, p->data);
		cout << p->data;//		输出上一层的根节点(位于栈顶)
		p = p->rchild;//指针指向根节点的右子树

	}
	return true;	
}

ISSUES:

一、还需要在:

最后加上一个限定条件,判定程序结束(停止退出循环):

所有节点都输出完毕了,程序即停止运行,也就是说:

栈为空,且指针为空

二、是否有必要再构造新变量q,存放出栈的根结点?

是否必须如同(和)PPT答案一样,再构造一个变量来存放出栈时的那个根结点?

如果不这样像上述Project 1一样的话:

我感觉好像没什么问题:

Pop的过程中p原来的值被覆盖掉了,但是两种写法最终结果好像都是p指向右子树

但是这种都是自己的猜测,存疑,希望大家看看有没有问题

不过(另外)值得一提的是:

不构造新变量q会出现以下警告:【但是如果构造新变量q,也会出现以下警告,所以没什么用哈哈哈】

不构造新变量的最终程序成品:

Status InOrderTraverse(BiTree T)
{
	BiTree p = T;//用于访问结点的指针
	SqStack S;
	InitStack(S);
	while (p || StackEmpty(S))
	{
		if (p)//p不为空,有(根)结点
				//另外这里注意,我们无法构造定义出“空结点/空树”,不要浪费力气了
		{
			Push(S, p->data);//		把根结点存到栈里
			p->lchild;//		访问(指针指向)左子树
		}
		else//(根)结点为空
		{
			Pop(S, p->data);
			cout << p->data;//		输出上一层的根节点(位于栈顶)
			p = p->rchild;//指针指向根节点的右子树
		}
	}	
	return true;	
}

构造新变量的最终程序成品:(标准答案)

Status InOrderTraverse(BiTree T)
{
	BiTree p = T;
	SqStack S;
	InitStack(S);
	while (p || StackEmpty(S))
	{
		if (p)
		{
			Push(S, p->data);
			p->lchild;
		}
		else
		{
			BiTree q = NULL;
			Pop(S, q->data);
			cout << q->data;
			p = q->rchild;
		}
	}	
	return true;	
}

注释版本:

Status InOrderTraverse(BiTree T)
{
	BiTree p = T;//用于访问结点的指针
	SqStack S;
	InitStack(S);
	while (p || StackEmpty(S))
	{
		if (p)//p不为空,有(根)结点
				//另外这里注意,我们无法构造定义出“空结点/空树”,不要浪费力气了
		{
			Push(S, p->data);//		把根结点存到栈里
			p->lchild;//		访问(指针指向)左子树
		}
		else//(根)结点为空
		{
			BiTree q = NULL;//用于访问结点的指针
			Pop(S, q->data);
			cout << q->data;//		输出上一层的根节点(位于栈顶)
			p = q->rchild;//指针指向根节点的右子树
		}
	}	
	return true;	
}

二叉树层次遍历算法:


核心思路:

我们这里写层次遍历算法,和前面写的中序遍历不一样

不是通过:

  1. 存储根节点
  2. 让指针不断循环
  3. 访问左子树,输出左子树

以及

  1. 输出根节点
  2. 访问并输出右子树

来实现访问遍历整棵树的所有节点,而是通过不断地循环进行:

  1. 出队(队头结点)

    注意:在每次循环第一步出队的过程中
    与此同时(在我们进行出队的操作的过程中)我们也将队列的头结点赋给指针(a)

    也即是说,在每次循环的过程中,a都会不断变化,不断指向循环开始时的队头结点(队列的第一个节点)

  2. 输出队头结点(根节点)

  3. 入队左孩子(如果有的话)

  4. 入队右孩子(如果有的话)


    前置条件:(原创版本)

#include<iostream>
using namespace std;
#include<stdlib.h>//存放exit

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

typedef char QElemType;
typedef int Status;         //函数调用状态
#define MAXQSIZE 100  //初始大小为100,可按需修改

struct QNode
{
    QElemType data;
    QNode* next;
};
typedef QNode* QuenePtr;//Pointer

struct LinkQueue
{
    QuenePtr front; // 队头指针
    QuenePtr rear; // 队尾指针
   // QNode* front; // 队头指针
    //QNode* rear; // 队尾指针
};


typedef QElemType TElemtype;//根据需求情况修改
typedef TElemtype SqBiTree;//sequence binary tree
//binary:二进制的; 二元的; 由两部分组成的;
SqBiTree bt;//binary tree

struct BiNode//二叉链表存储结构
{
    TElemtype data;
    struct
        BiNode* lchild, * rchild;
    //左右孩子指针
};
typedef BiNode* BiTree;

struct TriNode//trinary:三元的
{
    TElemtype data;
    struct
        BiNode* lchild, * rchild, * parent;
};
typedef TriNode* TriTree;

Status InitQueue(LinkQueue& Q)//初始化
{
    Q.front = Q.rear = new QNode;
    if (!Q.front)
        return false;
    Q.rear->next = NULL;
    return true;
}

Status DesQueue(LinkQueue& Q)//销毁
{
    while (Q.front)
    {
        QNode* p = Q.front->next;
        delete (Q.front);
        Q.front = p;
    }
    //也可以直接指定指针rear暂时储存Q.front->next的地址,反正他放在这闲着也没事
    //Q.rear=Q.front->next; free(Q.front); Q.front=Q.rear;
    return OK;
}

Status EnQueue(LinkQueue& Q, QElemType e)//入队
{
    QNode* p = new QNode;
    //QNode* p = (QuenePtr)malloc(sizeof(QNode));
    p->data = e;
    p->next = NULL;
    Q.rear->next = p;
    Q.rear = p;
    return OK;
}

Status DeQueue(LinkQueue& Q, QElemType e)//出队
{
    if (Q.front == Q.rear) return ERROR;
    QNode* p = Q.front->next;
    e = p->data;//保存删除的信息
    Q.front->next = p->next;
    if (Q.rear == p)
        Q.rear = Q.front;
    delete p;
    return true;
}

Status GetHead(LinkQueue Q, QElemType& e)
{
    if (Q.front == Q.rear) return ERROR;
    e = Q.front->next->data;
    return OK;
}

Status QueneEmpty(LinkQueue& Q)
{
    if (Q.front == Q.rear)
        return true;
    else
        return false;
 }

函数实现:(原创)

void LevelOrder(BiNode* b)//层次遍历
{
    BiNode* a = b;
    LinkQueue Q;
    InitQueue(Q);
    EnQueue(Q, b->data);
    //注意:不是    EnQueue(Q, a->data);     !!!!!!
    //把头结点放进队列(入队)
    while (!QueneEmpty(Q))
    {
        DeQueue(Q,a->data);
        cout << a->data;
        if(a->lchild)
            EnQueue(Q, a->lchild->data);
        if (a->rchild)
            EnQueue(Q, a->rchild->data);
    }
}

ISSUES:

(1):    BiNode* a = b;

    其实这里我没想给他赋初值,但是不弄就会报错。而如果我写成

    BiTree a = NULL;

格式虽然不会报错,但是也会出现如下预警:


至于PPT上的标准答案,我觉得是一坨大便,大可不必看,直接看我这个版本的就行/即可

猜你喜欢

转载自blog.csdn.net/Zz_zzzzzzz__/article/details/129633127