二叉树实现及应用(C语言模拟实现可以存放任意结点的栈、队列,二叉树遍历的递归与非递归实现,附上源码和实验报告,用了自取)

news2024/11/16 8:38:38

XI`AN TECHNOLOGICAL UNIVERSITY

目录

课程设计报告

1绪论

2课程设计目的和内容

3算法的基本思想

1 .建立二叉树结构     

   建立二叉树时,要先明确是按哪一种遍历规则输入,该二叉树是按你所输入的遍历规则来建立的。本实验用的先序遍历行建树。二叉树用链表存储来实现,因此要先定义一个二叉树链表存储结构。因此要先定义一个结构体。此结构体的每个结点都是由数据域data、左指针域Lchild、右指针域Rchild组成,两个指针域分别指向该结点的左、右孩子。

2. 输入二叉树元素 

    输入二叉树时,是按上面所确定的遍历规则输入的。最后,用一个返回值来表示所需要的结果.

3.  先序遍历二叉树 

     当二叉树为非空时,执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。

4. 中序遍历二叉树 

    当二叉树为非空时,程序执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。

5.  后序遍历二叉树 

     当二叉树为非空时,程序执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。

6.  非递归方式的先序遍历:

① 输出节点P,然后将其入栈,再看P的左孩子是否为空;

② 若P的左孩子不为空,则置P的左孩子为当前节点,重复①的操作;

③ 若P的左孩子为空,则将栈顶节点出栈,但不输出,并将出栈节点的右孩子置为当前节点,看其是否为空;

④ 若不为空,则循环至①操作;

⑤ 如果为空,则继续出栈,但不输出,同时将出栈节点的右孩子置为当前节点,看其是否为空,重复④和⑤操作;

⑥ 直到当前节点P为NULL并且栈空,遍历结束。

7.  非递归方式的中序遍历:

① 若P的左孩子不为空,则将P入栈并将P的左孩子置为当前节点,然后再对当前节点进行相同的处理;

② 若P的左孩子为空,则输出P节点,而后将P的右孩子置为当前节点,看其是否为空;

③ 若不为空,则重复①和②的操作;

④ 若为空,则执行出栈操作,输出栈顶节点,并将出栈的节点的右孩子置为当前节点,看起是否为空,重复③和④的操作;

⑤ 直到当前节点P为NULL并且栈为空,则遍历结束。

8.  非递归的后序遍历:

① 先将节点P入栈;

② 若P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右孩子已经被输出,则可以直接输出节点P,并将其出栈,将出栈节点P标记为上一个输出的节点,再将此时的栈顶结点设为当前节点;

③ 若不满足②中的条件,则将P的右孩子和左孩子依次入栈,当前节点重新置为栈顶结点,之后重复操作②;

④ 直到栈空,遍历结束。

9.  层次遍历二叉树:

4测试数据

5.源程序

5心得体会

源码


课程设计报告

实验课程名称   

专    业:         

班    级:              

姓    名:                 

学    号:            

实验学时:                        

指导教师:                     

成    绩:                         

        

               

                 

1绪论

现代社会生活中,计算机扮演着重要角色,而随着计算机运行速度的不断加快,对数据的处理能力也日益增强,因此,程序所涉及的数据很多,如何科学有效的对数据进行操作,使得计算机的时间和空间利用率最高是一个问题。针对这样的问题,我选择了二叉树对数据的各种操作作为我的课程设计主题,希望通过二叉树来提高对数据的处理能力,促进对数据结构课程的理解。

在二叉树的应用中,常常要求在树中查找具有某种特征的结点,或者对树中全部结点逐一进行某种处理,这就是二叉树的遍历问题。

对二叉树的数据结构进行定义,建立一颗二叉树,然后进行各种实验操作。

2课程设计目的和内容

(1)问题分析:建立一个二叉树,并对其进行4种遍历(前中后层)

(2)功能要求:使用递归和非递归,计算二叉树中节点的个数,树的深度等

(3)输入的形式和输入值的范围:采用c语言、自我实现栈和队列的代码

         输入值为一个可以满足二叉树存在的先序遍历序列

(4)输出的形式: (通过自己进行终端输入), 递归输出二叉树的先序遍历、中序遍历、后序遍历,非递归二叉树的先序遍历、中序遍历、后序遍历(使用栈),  二叉树的层序遍历(使用队列), 计算二叉树中结点个数的计算,  实现树的深度的计算

3算法的基本思想

1 .建立二叉树结构     

   建立二叉树时,要先明确是按哪一种遍历规则输入,该二叉树是按你所输入的遍历规则来建立的。本实验用的先序遍历行建树。二叉树用链表存储来实现,因此要先定义一个二叉树链表存储结构。因此要先定义一个结构体。此结构体的每个结点都是由数据域data、左指针域Lchild、右指针域Rchild组成,两个指针域分别指向该结点的左、右孩子。

2. 输入二叉树元素 

    输入二叉树时,是按上面所确定的遍历规则输入的。最后,用一个返回值来表示所需要的结果.

3.  先序遍历二叉树 

     当二叉树为非空时,执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。

4. 中序遍历二叉树 

    当二叉树为非空时,程序执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。

5.  后序遍历二叉树 

     当二叉树为非空时,程序执行以下三个操作:访问根结点、先序遍历左子树、先序遍历右子树。

6.  非递归方式的先序遍历:

① 输出节点P,然后将其入栈,再看P的左孩子是否为空;

② 若P的左孩子不为空,则置P的左孩子为当前节点,重复①的操作;

③ 若P的左孩子为空,则将栈顶节点出栈,但不输出,并将出栈节点的右孩子置为当前节点,看其是否为空;

④ 若不为空,则循环至①操作;

⑤ 如果为空,则继续出栈,但不输出,同时将出栈节点的右孩子置为当前节点,看其是否为空,重复④和⑤操作;

⑥ 直到当前节点P为NULL并且栈空,遍历结束。

7.  非递归方式的中序遍历:

① 若P的左孩子不为空,则将P入栈并将P的左孩子置为当前节点,然后再对当前节点进行相同的处理;

② 若P的左孩子为空,则输出P节点,而后将P的右孩子置为当前节点,看其是否为空;

③ 若不为空,则重复①和②的操作;

④ 若为空,则执行出栈操作,输出栈顶节点,并将出栈的节点的右孩子置为当前节点,看起是否为空,重复③和④的操作;

⑤ 直到当前节点P为NULL并且栈为空,则遍历结束。

8.  非递归的后序遍历:

① 先将节点P入栈;

② 若P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右孩子已经被输出,则可以直接输出节点P,并将其出栈,将出栈节点P标记为上一个输出的节点,再将此时的栈顶结点设为当前节点;

③ 若不满足②中的条件,则将P的右孩子和左孩子依次入栈,当前节点重新置为栈顶结点,之后重复操作②;

④ 直到栈空,遍历结束。

9.  层次遍历二叉树:

10. 计算根节点的个数

11. 计算二叉树的深度

 

4测试数据

5.源程序

#include<stdio.h>

#include<stdlib.h>

#include<assert.h>

#include<string.h>

//建立一个二叉树,并对其进行4种遍历(前中后层)。

//[要求] 使用递归和非递归,计算二叉树中节点的个数,树的深度。

// 使用c语言

// 树结构体

typedef struct _BNode

{

    char m_value;

    struct _BNode* m_left;

    struct _BNode* m_right;

}BNode;

// 存放树结点的栈结构体

typedef struct BNode* DataType;

typedef struct _Stack

{

    DataType* array;

    int capacity;

    int size;

}Stack;

// 存放树结点的队列结构体

typedef struct BNode* QDataType;

typedef struct QNode

{

    QDataType data;          //结点结构体的定义

    struct QNode* next;      //结点中保存着数据域与指针域

}QNode;

typedef struct Queue

{

    struct QNode* front; // 队列结构体中

    struct QNode* back;      // 存放着标记队列队头与队尾的两个指针

}Queue;

QNode* QueueBuyNode(QDataType data)

{

    QNode* newnode = (QNode*)malloc(sizeof(QNode));

    if (NULL == newnode)

    {

        assert(0);

        printf("BuyNode !!!\n");

    }

    newnode->data = data;

    newnode->next = NULL;

    return newnode;

}

// 初始化队列

void QueueInit(Queue* q)

{

    assert(q);

    q->back = NULL;

    q->front = NULL;

}

// 队尾入队列

void QueuePush(Queue* q, QDataType data)

{

    assert(q);

    // 0、创建一个新结点进行尾插

    QNode* newnode = QueueBuyNode(data);

    // 1、队列中没有结点

    if (QueueEmpty(q))

    {

        q->front = newnode;

        q->back = newnode;

    }

    else

    {

        // 2、队列中有结点

        q->back->next = newnode;

        q->back = newnode;

    }

}

// 队头出队列

void QueuePop(Queue* q)

{

    assert(q);

    // 1、队列中没有元素

    if (QueueEmpty(q))

        return;

    // 2、队列中只有一个元素

    else if (q->back == q->front)

    {

        free(q->front);

        q->front = NULL;

        q->back = NULL;

    }

    // 3、队列中有多个元素

    else

    {

        QNode* del = q->front;

        q->front = del->next;

        free(del);

    }

}

// 获取队列头部元素

QDataType Queuefront(Queue* q)

{

    assert(q);

    return q->front->data;

}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0

int QueueEmpty(Queue* q)

{

    assert(q);

    return NULL == q->back;

}

// 销毁队列

void QueueDestroy(Queue* q)

{

    assert(q);

    QNode* cur = q->front;

    while (cur)

    {

        q->front = cur->next;

        free(cur);

        cur = q->front;

    }

    q->front = NULL;

    q->back = NULL;

}

// 栈的初始化

void StackInit(Stack* ps)

{

    ps->array = (DataType*)malloc(sizeof(DataType) * 3);

    if (NULL == ps->array)

    {

        assert(0);

        printf("StackInit:malloc 申请空间失败!!!\n");

    }

    ps->size = 0;

    ps->capacity = 3;

}

void CheckStackCapacity(Stack* ps)

{

    assert(ps);

    if (ps->size == ps->capacity)

    {

        // 1、开辟新空间

        int newcapacity = ps->capacity * 2;

        char* temp = malloc(sizeof(DataType) * newcapacity);

        if (NULL == temp)

        {

            assert(0);

            printf("CheckStackCapacity :malloc fail!!!\n");

        }

        // 2、转移旧空间

        //void* memcpy(void* dest, const void* src, size_t count);

        memcpy(temp, ps->array, sizeof(DataType) * ps->size);

        // 3、释放旧空间

        free(ps->array);

        // 4、使用新空间

        ps->array = temp;

        ps->capacity = newcapacity;

    }

}

// 入栈

void StackPush(Stack* ps, DataType data)

{

    CheckStackCapacity(&ps);

    ps->array[ps->size] = data;

    ps->size++;

}

// 出栈

void StackPop(Stack* ps)

{

    if (StackEmpty(ps))

    {

        return;

    }

    ps->size--;

}

// 获取栈顶元素

DataType Stacktop(Stack* ps)

{

    assert(ps);

    return ps->array[ps->size - 1];

}

// 获取栈中存放元素个数

int StackSize(Stack* ps)

{

    assert(ps);

    return ps->size;

}

// 检测栈中是否为空

int StackEmpty(Stack* ps)

{

    assert(ps);

    return 0 == ps->size;

}

// 销毁栈

void StackDestory(Stack* ps)

{

    assert(ps);

    free(ps->array);

    ps->array = NULL;

    ps->size = 0;

    ps->capacity = 0;

}

//建立一个二叉树

BNode* BuyNode(char value)

{

    BNode* newnode = (BNode*)malloc(sizeof(BNode));

    newnode->m_value = value;

    newnode->m_left = NULL;

    newnode->m_right = NULL;

    return newnode;

}

BNode* Create(char array[], int size, int* index)

{

    BNode* root = NULL;

    if ((*index) < size && array[*index] != '#')

    {

        root = BuyNode(array[*index]);

        ++(*index);

        root->m_left = Create(array, size, index);

        ++(*index);

        root->m_right = Create(array, size, index);

    }

    return root;

}

BNode* _Create(char array[], int size)

{

    int index = 0;

    return Create(array, size, &index);

}

// 递归遍历

// 先序(递归)遍历

void Preoder_Recursion(BNode* root)

{

    if (root == NULL)

        return;

    printf("%c ", root->m_value);

    Preoder_Recursion(root->m_left);

    Preoder_Recursion(root->m_right);

}

// 中序(递归)遍历

void Inoder_Recursion(BNode* root)

{

    if (root == NULL)

        return;

    Inoder_Recursion(root->m_left);

    printf("%c ", root->m_value);

    Inoder_Recursion(root->m_right);

}

// 中序(递归)遍历

void Postoder_Recursion(BNode* root)

{

    if (root == NULL)

        return;

    Postoder_Recursion(root->m_left);

    Postoder_Recursion(root->m_right);

    printf("%c ", root->m_value);

}

///

// 层序遍历 使用队列

void BinaryTreeLevelOrder(BNode* root)

{

    Queue q;

    QueueInit(&q);

    QueuePush(&q, root);

    while (!QueueEmpty(&q))

    {

        // a. 从队头取一个结点

        BNode* cur = Queuefront(&q);

        // b.遍历该结点

        printf("%c ", cur->m_value);

        // c. 如果cur有左孩子则入队列,有右孩子则入队列

        if (cur->m_left)

            QueuePush(&q, cur->m_left);

        if (cur->m_right)

            QueuePush(&q, cur->m_right);

        // d. 遍历之后出队列

        QueuePop(&q);

    }

    QueueDestroy(&q);

    printf("\n");

}

// 非递归遍历

// 先序(非递归)遍历

void Preoder_Non_recursive(BNode* root)

{

    Stack s;

    StackInit(&s);

    if (root == NULL)

        return;

    BNode* cur = NULL;

    StackPush(&s, root);         // 将根节点入栈

    while (!StackEmpty(&s))

    {

        cur = Stacktop(&s);      // cur指针每次指向栈顶元素

        printf("%c ", cur->m_value);  // 先序遍历根节点

        StackPop(&s); // 遍历一次结点之后将该结点出栈       

        if (cur->m_right)            // 先入栈根的右节点再入栈根的左结点

            StackPush(&s, cur->m_right);

        if (cur->m_left)

            StackPush(&s, cur->m_left);

    }

    StackDestory(&s);

}

// 中序(非递归)遍历

void Inoder_Non_recursive(BNode* root)

{

    Stack s;

    StackInit(&s);

    while (root != NULL || !StackEmpty(&s)) {

        while (root != NULL) {

            StackPush(&s, root);

            root = root->m_left;

        }

        root = Stacktop(&s);

        StackPop(&s);

        printf("%c ", root->m_value);

        root = root->m_right;

    }

}

// 后序(非递归)遍历

void Postoder_Non_recursive(BNode* root)

{

    Stack s;

    StackInit(&s);

    BNode* prev = NULL;

    while (root || !StackEmpty(&s))

    {

        //循环每次迭代都是才开始访问树

        while (root) // 左路节点入栈

        {

            StackPush(&s, root);

            root = root->m_left;

        } // 左路遇空

        BNode* top = Stacktop(&s);

        if (top->m_right == NULL || top->m_right == prev)

        {

            printf("%c ", top->m_value); // 后序遍历

            prev = top; // 记录

            StackPop(&s);

        }

        else

        {

            root = top->m_right; // 访问右路节点,再次进入循环继续遍历左路

        }

    }

}

// 二叉树节点个数

int BinaryTreeSize(BNode* root)

{

    if (NULL == root)

        return 0;

    return 1 + BinaryTreeSize(root->m_left) + BinaryTreeSize(root->m_right);

}

// 二叉树的高度

int BinaryTreeHeight(BNode* root)

{

    if (NULL == root)

        return 0;

    // 利用递归来求每个结点树的高度

    // 先求左右子树的高度

    // 返回高的那棵树+1

    int left = BinaryTreeHeight(root->m_left);

    int right = BinaryTreeHeight(root->m_right);

    return left > right ? left + 1 : right + 1;

}

int main()

{

    printf("请采用先序遍历输入数据\n");

    char array[100] = { '#' };

    gets_s(array, 99);

    BNode* root = _Create(array, strlen(array));

    printf("\n以下打印均采用递归方式\n");

    printf("进行先序遍历打印输出\n");

    Preoder_Recursion(root);

    printf("\n");

    printf("进行中序遍历打印输出\n");

    Inoder_Recursion(root);

    printf("\n");

    printf("进行后序遍历打印输出\n");

    Postoder_Recursion(root);

    printf("\n");

    printf("\n以下打印均采用非递归方式(使用栈)\n");

    printf("进行先序遍历打印输出\n");

    Preoder_Non_recursive(root);

    printf("\n");

    printf("进行中序遍历打印输出\n");

    Inoder_Non_recursive(root);

    printf("\n");

    printf("进行后序遍历打印输出\n");

    Postoder_Non_recursive(root);

    printf("\n");

    printf("\n进行层序遍历打印输出(使用队列)\n");

    BinaryTreeLevelOrder(root);

    printf("\n");

    printf("该二叉树的结点个数为:%d\n", BinaryTreeSize(root));

    printf("该二叉树的高度为:%d\n", BinaryTreeHeight(root));

    printf("\n");

    return 0;

}

5心得体会

对于非递归算法,我使用了栈结构和队列结构,分别用于前序遍历、中序、后序遍历、非递归层次序遍历方法中。使用栈和队列的过程中,我在实践中又学习了栈和队列的一些知识,提

高了各种逻辑结构之间的综合运用能力。通过这次课程设计,我发现,知识不仅仅是在课本上,多查阅一些资料能够更好的完成课题,并且,只有把书本上的知识实际应用下来,才能把知识学到融会贯通,而且学习过程中一定不要怕繁琐,调试过程中一定会遇到一些难以解决的问题,这个时候我需要和老师和同学去请教,还有慢慢耐心地调试,才可以。

源码(点个小赞呗)

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
//建立一个二叉树,并对其进行4种遍历(前中后层)。
//[要求] 使用递归和非递归,计算二叉树中节点的个数,树的深度。
// 使用c语言

// 树结构体
typedef struct _BNode
{
	char m_value;
	struct _BNode* m_left;
	struct _BNode* m_right;
}BNode;

// 存放树结点的栈结构体
typedef struct BNode* DataType;
typedef struct _Stack
{
	DataType* array;
	int capacity;
	int size;
}Stack;

// 存放树结点的队列结构体
typedef struct BNode* QDataType;
typedef struct QNode
{
	QDataType data;			//结点结构体的定义
	struct QNode* next;		//结点中保存着数据域与指针域
}QNode;
typedef struct Queue
{
	struct QNode* front;	// 队列结构体中
	struct QNode* back;		// 存放着标记队列队头与队尾的两个指针
}Queue;


QNode* QueueBuyNode(QDataType data)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (NULL == newnode)
	{
		assert(0);
		printf("BuyNode !!!\n");
	}
	newnode->data = data;
	newnode->next = NULL;
	return newnode;
}

// 初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->back = NULL;
	q->front = NULL;
}

// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	// 0、创建一个新结点进行尾插
	QNode* newnode = QueueBuyNode(data);

	// 1、队列中没有结点
	if (QueueEmpty(q))
	{
		q->front = newnode;
		q->back = newnode;
	}
	else
	{
		// 2、队列中有结点
		q->back->next = newnode;
		q->back = newnode;
	}
}

// 队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	// 1、队列中没有元素
	if (QueueEmpty(q))
		return;

	// 2、队列中只有一个元素
	else if (q->back == q->front)
	{
		free(q->front);
		q->front = NULL;
		q->back = NULL;
	}

	// 3、队列中有多个元素
	else
	{
		QNode* del = q->front;
		q->front = del->next;
		free(del);
	}
}

// 获取队列头部元素
QDataType Queuefront(Queue* q)
{
	assert(q);
	return q->front->data;
}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	return NULL == q->back;
}

// 销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->front;
	while (cur)
	{
		q->front = cur->next;
		free(cur);
		cur = q->front;
	}
	q->front = NULL;
	q->back = NULL;
}

// 栈的初始化
void StackInit(Stack* ps)
{
	ps->array = (DataType*)malloc(sizeof(DataType) * 3);
	if (NULL == ps->array)
	{
		assert(0);
		printf("StackInit:malloc 申请空间失败!!!\n");
	}
	ps->size = 0;
	ps->capacity = 3;
}

void CheckStackCapacity(Stack* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		// 1、开辟新空间
		int newcapacity = ps->capacity * 2;
		char* temp = malloc(sizeof(DataType) * newcapacity);
		if (NULL == temp)
		{
			assert(0);
			printf("CheckStackCapacity :malloc fail!!!\n");
		}

		// 2、转移旧空间
		//void* memcpy(void* dest, const void* src, size_t count);
		memcpy(temp, ps->array, sizeof(DataType) * ps->size);

		// 3、释放旧空间
		free(ps->array);

		// 4、使用新空间
		ps->array = temp;
		ps->capacity = newcapacity;
	}
}

// 入栈
void StackPush(Stack* ps, DataType data)
{
	CheckStackCapacity(&ps);
	ps->array[ps->size] = data;
	ps->size++;
}

// 出栈
void StackPop(Stack* ps)
{
	if (StackEmpty(ps))
	{
		return;
	}
	ps->size--;
}

// 获取栈顶元素
DataType Stacktop(Stack* ps)
{
	assert(ps);
	return ps->array[ps->size - 1];
}

// 获取栈中存放元素个数
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->size;
}

// 检测栈中是否为空
int StackEmpty(Stack* ps)
{
	assert(ps);
	return 0 == ps->size;
}

// 销毁栈
void StackDestory(Stack* ps)
{
	assert(ps);
	free(ps->array);
	ps->array = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

//建立一个二叉树
BNode* BuyNode(char value)
{
	BNode* newnode = (BNode*)malloc(sizeof(BNode));
	newnode->m_value = value;
	newnode->m_left = NULL;
	newnode->m_right = NULL;
	return newnode;
}
BNode* Create(char array[], int size, int* index)
{
	BNode* root = NULL;
	if ((*index) < size && array[*index] != '#')
	{
		root = BuyNode(array[*index]);
		++(*index);
		root->m_left = Create(array, size, index);
		++(*index);
		root->m_right = Create(array, size, index);
	}
	return root;
}

BNode* _Create(char array[], int size)
{
	int index = 0;
	return Create(array, size, &index);
}

// 递归遍历

// 先序(递归)遍历
void Preoder_Recursion(BNode* root)
{
	if (root == NULL)
		return;
	printf("%c ", root->m_value);
	Preoder_Recursion(root->m_left);
	Preoder_Recursion(root->m_right);
}
// 中序(递归)遍历
void Inoder_Recursion(BNode* root)
{
	if (root == NULL)
		return;
	Inoder_Recursion(root->m_left);
	printf("%c ", root->m_value);
	Inoder_Recursion(root->m_right);
}
// 中序(递归)遍历
void Postoder_Recursion(BNode* root)
{
	if (root == NULL)
		return;
	Postoder_Recursion(root->m_left);
	Postoder_Recursion(root->m_right);
	printf("%c ", root->m_value);
}

///
// 层序遍历 使用队列
void BinaryTreeLevelOrder(BNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
		// a. 从队头取一个结点 
		BNode* cur = Queuefront(&q);
		// b.遍历该结点
		printf("%c ", cur->m_value);

		// c. 如果cur有左孩子则入队列,有右孩子则入队列
		if (cur->m_left)
			QueuePush(&q, cur->m_left);
		if (cur->m_right)
			QueuePush(&q, cur->m_right);
		// d. 遍历之后出队列
		QueuePop(&q);
	}
	QueueDestroy(&q);
	printf("\n");
}

// 非递归遍历

// 先序(非递归)遍历
void Preoder_Non_recursive(BNode* root)
{
	Stack s;
	StackInit(&s);
	if (root == NULL)
		return;
	BNode* cur = NULL;
	StackPush(&s, root);			// 将根节点入栈
	while (!StackEmpty(&s))
	{
		cur = Stacktop(&s);		// cur指针每次指向栈顶元素
		printf("%c ", cur->m_value);	// 先序遍历根节点
		StackPop(&s);	// 遍历一次结点之后将该结点出栈		
		if (cur->m_right)				// 先入栈根的右节点再入栈根的左结点
			StackPush(&s, cur->m_right);
		if (cur->m_left)
			StackPush(&s, cur->m_left);
	}
	StackDestory(&s);
}
// 中序(非递归)遍历
void Inoder_Non_recursive(BNode* root)
{
	Stack s;
	StackInit(&s);
	while (root != NULL || !StackEmpty(&s)) {
		while (root != NULL) {
			StackPush(&s, root);
			root = root->m_left;
		}
		root = Stacktop(&s);
		StackPop(&s);
		printf("%c ", root->m_value);
		root = root->m_right;
	}
}
// 后序(非递归)遍历
void Postoder_Non_recursive(BNode* root)
{
	Stack s;
	StackInit(&s);
	BNode* prev = NULL;
	while (root || !StackEmpty(&s))
	{
		//循环每次迭代都是才开始访问树
		while (root) // 左路节点入栈
		{
			StackPush(&s, root);
			root = root->m_left;
		} // 左路遇空

		BNode* top = Stacktop(&s);

		if (top->m_right == NULL || top->m_right == prev)
		{
			printf("%c ", top->m_value); // 后序遍历
			prev = top; // 记录
			StackPop(&s);
		}
		else
		{
			root = top->m_right; // 访问右路节点,再次进入循环继续遍历左路
		}
	}
}
// 二叉树节点个数
int BinaryTreeSize(BNode* root)
{
	if (NULL == root)
		return 0;
	return 1 + BinaryTreeSize(root->m_left) + BinaryTreeSize(root->m_right);
}

// 二叉树的高度
int BinaryTreeHeight(BNode* root)
{
	if (NULL == root)
		return 0;

	// 利用递归来求每个结点树的高度
	// 先求左右子树的高度
	// 返回高的那棵树+1
	int left = BinaryTreeHeight(root->m_left);
	int right = BinaryTreeHeight(root->m_right);
	return left > right ? left + 1 : right + 1;
}

int main()
{
	printf("请采用先序遍历输入数据\n");
	char array[100] = { '#' };
	gets_s(array, 99);
	BNode* root = _Create(array, strlen(array));
	printf("\n以下打印均采用递归方式\n");
	printf("进行先序遍历打印输出\n");
	Preoder_Recursion(root);
	printf("\n");

	printf("进行中序遍历打印输出\n");
	Inoder_Recursion(root);
	printf("\n");

	printf("进行后序遍历打印输出\n");
	Postoder_Recursion(root);
	printf("\n");

	printf("\n以下打印均采用非递归方式(使用栈)\n");
	printf("进行先序遍历打印输出\n");
	Preoder_Non_recursive(root);
	printf("\n");

	printf("进行中序遍历打印输出\n");
	Inoder_Non_recursive(root);
	printf("\n");

	printf("进行后序遍历打印输出\n");
	Postoder_Non_recursive(root);
	printf("\n");

	printf("\n进行层序遍历打印输出(使用队列)\n");
	BinaryTreeLevelOrder(root);
	printf("\n");

	printf("该二叉树的结点个数为:%d\n", BinaryTreeSize(root));
	printf("该二叉树的高度为:%d\n", BinaryTreeHeight(root));
	printf("\n");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/136844.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第六章. 图解数组计算模块Numpy—数据的相关概念和创建数组

第六章. 图解数组计算模块Numpy 6.1 数据的相关概念和创建数组 Numpy是Python数组计算&#xff0c;矩阵运算和科学计算的核心库&#xff0c;它的用途是以数组的形式对数据进行操作&#xff0c;由于Numpy是通过C语言实现的&#xff0c;所以运算速度比较快。 1. Numpy的功能&…

技术贴 | SQL 编译与执行 -parser

前言SQL 编译与执行系列技术博客将按照以下顺序分别介绍整个 SQL 执行引擎。图一 SQL 编译与执行研读流程parser 部分&#xff0c;包括词法解析和语法解析。compile 部分&#xff0c;包括语义解析以及计划的构建。optimize 部分&#xff0c;包括计划的优化。exec 部分&#xff…

十四、TCP多线程、原子类AtomicInteger、日志、枚举

tcp多线程 tcp客户端 多线程收发代码 package com.heima.test2;import java.io.*; import java.net.Socket; import java.nio.charset.Charset; import java.util.Scanner;class ClientSend implements Runnable {Socket socket;Scanner sc new Scanner(System.in);public C…

2019年数维杯国际大学生数学建模B题无人机避障问题设计规划求解全过程文档及程序

2019年数维杯国际大学生数学建模 B题 无人机避障问题设计规划 问题重述&#xff1a; 任务1&#xff1a;假设无人机在飞行过程中不受风向、湿度等外界因素的影响&#xff0c;飞行速度和拍摄角度恒定&#xff0c;无人机对一定宽度的区域进行直线飞行模式航拍。执行此航拍的飞行…

SpringBoot(一): SpringBoot的创建和使用

Spring的创建和使用1. 什么是Spring&#xff1f;2. SpringBoot的优点3. SpringBoot项目的创建3.1 使用IDEA创建3.2 使用网页创建4. 项目目录介绍和运行4.1 目录介绍4.2 项目运行4.3 输出hello world4.4 约定大于配置1. 什么是Spring&#xff1f; Spring的诞生是为了简化Java程…

Spring-boot启动失败 Unregistering JMX-exposed beans on shutdown 异常处理

目录一、异常错误二、原因三、解决方法一、异常错误 Spring-boot启动Run时&#xff0c;出现 o.s.j.e.a.AnnotationMBeanExporter - Unregistering JMX-exposed beans on shutdown 错误 *************************** APPLICATION FAILED TO START Description: The Tomcat conn…

【小程序】包与数据共享

文章目录使用 npm 包Vant WeappAPI Promise化全局事件共享MobX分包分包概念使用分包独立分包分包预下载使用 npm 包 目前&#xff0c;小程序中已经支持使用 npm 安装第三方包&#xff0c;从而来提高小程序的开发效率。但是&#xff0c;在小程序中使用npm 包有如下 3 个限制&am…

【韩顺平Linux】学习笔记3

【韩顺平Linux】学习笔记3一、文件目录指令pwd指令 ls指令cd指令mkdir指令rmdir指令touch指令cp指令rm指令mv指令cat指令more指令less 指令echo指令 head指令tail指令> 指令 >>指令ln指令history指令二、时间日期指令三、查找指令四、压缩和解压一、文件目录指令 根目…

【前端】Vue项目:旅游App-(3)TabBar:点击active效果、点击路由跳转

文章目录目标代码与过程设置active主题颜色添加点击active效果点击路由跳转效果总代码修改或新增的文件common.cssindex.csstab-bar.vue目标 添加点击active效果实现点击路由跳转效果 上一篇TabBar搭建&#xff1a;【前端】Vue项目&#xff1a;旅游App-&#xff08;2&#xff…

LVGL学习笔记12 - 复选框CheckBox

目录 1. Parts 1.1 LV_PART_MAIN 1.2 LV_PART_INDICATOR 2. 状态 3. 样式 3.1 设置字符串颜色 3.2 设置点击框外框颜色 3.3 修改点击框弧度 3.4 修改字符串与点击框的间隔 4. 事件 复选框通过lv_checkbox_create创建。一个CheckBox由一个点击框加一个Label组成。 obj1 …

Minikube Mac 安装 使用

Minikube Mac 安装 使用 环境要求 硬件要求 至少 2核 CPUs2GB 以上内存20GB 以上磁盘空间网络环境容器或虚拟机, 例如: Docker, QEMU, Hyperkit, Hyper-V, KVM, Parallels, Podman, VirtualBox, or VMware Fusion/Workstation 本机环境 Mac Pro 10.13.6 Docker 18.09.1 …

半导体行业相关术语

目录 1.晶圆&#xff08;wafer&#xff09; 2. 自动化测试设备&#xff08;ATE Automatic Test Equipment&#xff09; 3.晶盒&#xff08;Cassette&#xff09; 4. 待测设备(DUT Device Under Test) 5. 探针接口板(PIB Prober Interface Board) 6. 设备接口板(DIB D…

干货 | web自动化总卡在文件上传和弹框处理上?

在有些场景中&#xff0c;需要上传文件&#xff0c;而 Selenium 无法定位到弹出的文件框&#xff0c;以及网页弹出的提醒。这些都是需要特殊的方式来处理。input 标签使用自动化上传&#xff0c;先定位到上传按钮&#xff0c;然后 send_keys 把路径作为值给传进去.如图所示&…

【计算机网络-物理层】通信基础

文章目录1 码元、速率、波特、带宽1.1 码元1.2 波特率1.3 比特率1.4 带宽1.5 相关例题2 奈氏准则、香农定理2.1 奈氏准则&#xff08;采样定理&#xff09;2.2 香农定理2.3 相关例题3 编码方式3.1 归零编码&#xff08;RZ&#xff09;3.2 非归零编码&#xff08;NRZ&#xff09…

【简单DP】[NOIP2007 普及组] 守望者的逃离

P1095 [NOIP2007 普及组] 守望者的逃离 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)题意&#xff1a;思路&#xff1a;独立做出来的一道DP&#xff01;一开始我去模拟过程找子问题&#xff0c;然后去找阶段是什么本来想的是以路程作为阶段&#xff0c;但是1e8数组开不下那么…

如何看待PyTorch 2.0?

作者&#xff5c;吴育昕 1 为什么是TorchDynamo Graph capture 把用户 Python 写的模型代码变成 graph&#xff0c;是一切编译的根基。而 PyTorch 在试了这么多方案之后似乎已经锁定 TorchDynamo 作为 graph capture 的未来方向了&#xff0c;所以写一点关于 TorchDynamo 的…

假如面试官问你Babel的原理该怎么回答

1. 什么是 Babel 简单地说&#xff0c;Babel 能够转译 ECMAScript 2015 的代码&#xff0c;使它在旧的浏览器或者环境中也能够运行。 // es2015 的 const 和 arrow function const add (a, b) > a b;// Babel 转译后 var add function add(a, b) {return a b; };Babel…

pwr | 谁说样本量计算是个老大难问题!?(二)(独立样本均值篇)

1写在前面 上次介绍了两组发生率的样本量计算方法&#xff0c;通过pwr包进行计算非常简单&#xff0c;可以有效地减少我们的工作量。&#x1f618; 有时候我们想比较两组之间的均值&#xff0c;如何计算样本量又一次成了老大难问题。&#x1f912; 本期我们还是基于pwr包&#…

【自学Java】Windows安装PyCharm IDE

Windows安装PyCharm IDE PyCharm下载 PyCharm下载地址 https://www.jetbrains.com/pycharm/PyCharm下载 打开上面的链接&#xff0c;打开 Python 的开发工具 PyCharm 的下载页面&#xff0c;如下图所示&#xff1a; 这里我们点击 Download&#xff0c;跳转到新的页面&#…

错过短视频,微博奔向新浪

以后新浪或许会被叫做“微博新浪”。 2022年12月23日晚&#xff0c;港股微博发布公告称&#xff0c;拟斥资15亿元收购新浪网技术有限公司100%股权。此举被外界解读为微博将反向收购新浪。 曾经&#xff0c;微博还是新浪移动互联网时代的“船票”。随着门户网站逐渐凋零&#…