初识二叉树

一.二叉树的介绍

   1.二叉树是一种树状数据结构,由多个节点构成,每个节点最多有两个子节点,这两个节点称为左节点和右节点,一个节点的上一次称为它的父节点,下一层称为它的子节点,越往下走,节点越多,越往上走,节点越少,由下面一张图,你便容易清楚二叉树名字的得来。

2. 二叉树有以下特点:

1.一个有x层的二叉树,允许最多有2^(x)-1个节点。

2.第x层,最多有2^x个节点。

3.二叉树有一个根节点,是树的起始点,没有父节点。叶子节点是没有子节点的节点,它们位于树的末端。

3.二叉树又分为满二叉树和完全二叉树。

满二叉树:二叉树的每一层都是满的,即每个节点都有两个子节点(除了最后一层,可以有一个子节点),假如4层的二叉树,就有15个节点,下图示例。

完全二叉树:除了最后一层外,每一层的节点都是紧凑排列的,并且最后一层的节点从左到右依次填充。

二.二叉树的创建。

1.首先用一个结构体表示一个节点的数据、左子结点和右子节点。

struct tree{
	int data;//存放数据
	struct tree*lefttree;//左子节点 
	struct tree*righttree;//右子节点 
};

2.创建节点。

struct tree* creattreenode(int data)//返回结构体指针类型 
{
	struct tree* newtreenode=(struct tree*)malloc(sizeof(struct tree));//动态分配空间 
	newtreenode->data=data;
	newtreenode->lefttree=NULL;//此时新建的节点没有左子结点和右子节点,设置为空 
	newtreenode->righttree=NULL;
	return newtreenode;//返回新建的节点 
}

3.给节点插入对应的子节点。

void insert(struct tree*mytree,struct tree*mylefttree,struct tree*myrighttree) 
{
	mytree->lefttree=mylefttree;//将树的左右子节点与你想插入的左右子节点连接 
	mytree->righttree=myrighttree;
}

以这张图片为模板构建好二叉树,只需利用上述函数即可简单实现。

	struct tree*num0=creattreenode(0);//创建出对应节点 
	struct tree*num1=creattreenode(1);
	struct tree*num2=creattreenode(2);
	struct tree*num3=creattreenode(3);
	struct tree*num4=creattreenode(4);
	struct tree*num5=creattreenode(5);
	insert(num0,num1,num2);//插入操作 
	insert(num1,num3,num4);
	insert(num2,num5,NULL);

构建好后,便可以为遍历做好准备。

三.二叉树的遍历。

   二叉树的遍历分为先序遍历、中序遍历和后序遍历。

以上面的二叉树为模板介绍三种遍历

提前写好打印函数。

void print(struct tree*treenode)
{
	printf("%d\t",treenode->data); 
}

1.先序遍历:按照根节点,左孩子树,右孩子树的顺序遍历。

void pre(struct tree*treenode)
{
	if(treenode!=NULL)//一定要不为空才进行遍历,不然会死循环 
	{
		print(treenode);//根开始 
		pre(treenode->lefttree);//左子节点 
		pre(treenode->righttree);//右子节点 
	}
}

运行结果

0       1       3       4       2       5

2.中序遍历:按照左孩子树,根节点,右孩子树的顺序遍历。

只需更换一下位置即可

void mid(struct tree*treenode)
{
	if(treenode!=NULL)//一定要不为空才进行遍历,不然会死循环 
	{
		mid(treenode->lefttree);//左子节点开始 
		print(treenode);
		mid(treenode->righttree);
	}
} 

运行结果

3       1       4       0       5       2

3.后序遍历:按照左孩子树,右孩子树,根节点的顺序遍历。

 原理一样

void last(struct tree*treenode)
{
	if(treenode!=NULL)//一定要不为空才进行遍历,不然会死循环 
	{
		last(treenode->lefttree);//左子节点开始 
		last(treenode->righttree);
		print(treenode);
	}
} 

运行结果

3       4       1       5       2       0

对于三种遍历我是使用的递归的方式,如果不喜欢递归的话,可以使用栈去遍历二叉树。

1.栈实现先序遍历。

void prestack(struct tree*treenode)
{
	if(treenode==NULL)
	return;
	struct tree*stack[20];
	int stacksize=-1;
	struct tree*temp=treenode;
	while(stacksize!=-1||temp){//当栈全部输出,并且左右节点都为空,便会停止循环 
		while(temp){//按照根左右的先序遍历 
			print(temp);//打印走过的节点 
			stack[++stacksize]=temp;//将左子结点入栈 
			temp=temp->lefttree;
		}
		if(stacksize!=-1)//当左子节点无路可走,开始往右子节点遍历 
		{
			temp=stack[stacksize];//获取栈顶元素,用与输出 
			stacksize--;
			temp=temp->righttree;
		}
	}
}

运行结果

0       1       3       4       2       5

2.栈实现中序遍历

void midstack(struct tree*treenode)
{
	if(treenode==NULL)
	return;
	struct tree*stack[20];
	int stacksize=-1;
	struct tree*temp=treenode;
	while(stacksize!=-1||temp){
		while(temp){// 先到左子节点位置,把经过的位置入栈 
			stack[++stacksize]=temp;
			temp=temp->lefttree;
		}
		if(stacksize!=-1)//准备工作完成,出栈 
		{
			temp=stack[stacksize];
			stacksize--;
			print(temp);
			temp=temp->righttree;
		}
	}
}

运行结果

3       1       4       0       5       2

3.栈实现后序遍历

void laststack(struct tree*treenode)
{
	if(treenode==NULL)
	return;
	struct tree*stack[20];
	int stacksize=-1;
	struct tree*temp=treenode;
	struct tree*flag=NULL; //需要使用访问标记 
	while(temp){//先将左节点入队 
		stack[++stacksize]=temp;
		temp=temp->lefttree;
	}
	while(stacksize!=-1){
		temp=stack[stacksize--];
		if(temp->righttree==NULL||temp->righttree==flag)
		{
			print(temp);//被访问则打印当前节点 
			flag=temp;//改变标记位置 
		}
		else
		{//开始往右边访问 
			stack[++stacksize]=temp;
			temp=temp->righttree;
			while(temp){
				stack[++stacksize]=temp;
				temp=temp->lefttree;
			}
		}

	}
}

运行结果

3       4       1       5       2       0

最后附上全部代码

递归版

#include<stdio.h>
#include<stdlib.h>
struct tree{
	int data;//存放数据
	struct tree*lefttree;//左子节点 
	struct tree*righttree;//右子节点 
};
struct tree* creattreenode(int data)//返回结构体指针类型 
{
	struct tree* newtreenode=(struct tree*)malloc(sizeof(struct tree));//动态分配空间 
	newtreenode->data=data;
	newtreenode->lefttree=NULL;//此时新建的节点没有左子结点和右子节点,设置为空 
	newtreenode->righttree=NULL;
	return newtreenode;//返回新建的节点 
}
void insert(struct tree*mytree,struct tree*mylefttree,struct tree*myrighttree) 
{
	mytree->lefttree=mylefttree;//将树的左右子节点与你想插入的左右子节点连接 
	mytree->righttree=myrighttree;
}
void print(struct tree*treenode)
{
	printf("%d\t",treenode->data); 
}
void pre(struct tree*treenode)
{
	if(treenode!=NULL)//一定要不为空才进行遍历,不然会死循环 
	{
		print(treenode);//根开始 
		pre(treenode->lefttree);//左子节点 
		pre(treenode->righttree);//右子节点 
	}
}

void mid(struct tree*treenode)
{
	if(treenode!=NULL)//一定要不为空才进行遍历,不然会死循环 
	{
		mid(treenode->lefttree);//左子节点开始 
		print(treenode);
		mid(treenode->righttree);
	}
} 

void last(struct tree*treenode)
{
	if(treenode!=NULL)//一定要不为空才进行遍历,不然会死循环 
	{
		last(treenode->lefttree);//左子节点开始 
		last(treenode->righttree);
		print(treenode);
	}
} 
int main()
{
	struct tree*num0=creattreenode(0);//创建出对应节点 
	struct tree*num1=creattreenode(1);
	struct tree*num2=creattreenode(2);
	struct tree*num3=creattreenode(3);
	struct tree*num4=creattreenode(4);
	struct tree*num5=creattreenode(5);
	insert(num0,num1,num2);//插入操作 
	insert(num1,num3,num4);
	insert(num2,num5,NULL);
	pre(num0);
	printf("\n");
	mid(num0);
	printf("\n");
	last(num0);
	return 0;
}

栈版

#include<stdio.h>
#include<stdlib.h>
struct tree{
	int data;//存放数据
	struct tree*lefttree;//左子节点 
	struct tree*righttree;//右子节点 
};
struct tree* creattreenode(int data)//返回结构体指针类型 
{
	struct tree* newtreenode=(struct tree*)malloc(sizeof(struct tree));//动态分配空间 
	newtreenode->data=data;
	newtreenode->lefttree=NULL;//此时新建的节点没有左子结点和右子节点,设置为空 
	newtreenode->righttree=NULL;
	return newtreenode;//返回新建的节点 
}
void insert(struct tree*mytree,struct tree*mylefttree,struct tree*myrighttree) 
{
	mytree->lefttree=mylefttree;//将树的左右子节点与你想插入的左右子节点连接 
	mytree->righttree=myrighttree;
}
void print(struct tree*treenode)
{
	printf("%d\t",treenode->data); 
}
void prestack(struct tree*treenode)
{
	if(treenode==NULL)
	return;
	struct tree*stack[20];
	int stacksize=-1;
	struct tree*temp=treenode;
	while(stacksize!=-1||temp){//当栈全部输出,并且左右节点都为空,便会停止循环 
		while(temp){//按照根左右的先序遍历 
			print(temp);//打印走过的节点 
			stack[++stacksize]=temp;//将左子结点入栈 
			temp=temp->lefttree;
		}
		if(stacksize!=-1)//当左子节点无路可走,开始往右子节点遍历 
		{
			temp=stack[stacksize];//获取栈顶元素,用与输出 
			stacksize--;
			temp=temp->righttree;
		}
	}
}
void midstack(struct tree*treenode)
{
	if(treenode==NULL)
	return;
	struct tree*stack[20];
	int stacksize=-1;
	struct tree*temp=treenode;
	while(stacksize!=-1||temp){
		while(temp){// 先到左子节点位置,把经过的位置入栈 
			stack[++stacksize]=temp;
			temp=temp->lefttree;
		}
		if(stacksize!=-1)//准备工作完成,出栈 
		{
			temp=stack[stacksize];
			stacksize--;
			print(temp);
			temp=temp->righttree;
		}
	}
}
void laststack(struct tree*treenode)
{
	if(treenode==NULL)
	return;
	struct tree*stack[20];
	int stacksize=-1;
	struct tree*temp=treenode;
	struct tree*flag=NULL; //需要使用访问标记 
	while(temp){//先将左节点入队 
		stack[++stacksize]=temp;
		temp=temp->lefttree;
	}
	while(stacksize!=-1){
		temp=stack[stacksize--];
		if(temp->righttree==NULL||temp->righttree==flag)
		{
			print(temp);//被访问则打印当前节点 
			flag=temp;//改变标记位置 
		}
		else
		{//开始往右边访问 
			stack[++stacksize]=temp;
			temp=temp->righttree;
			while(temp){
				stack[++stacksize]=temp;
				temp=temp->lefttree;
			}
		}

	}
}
int main()
{
	struct tree*num0=creattreenode(0);//创建出对应节点 
	struct tree*num1=creattreenode(1);
	struct tree*num2=creattreenode(2);
	struct tree*num3=creattreenode(3);
	struct tree*num4=creattreenode(4);
	struct tree*num5=creattreenode(5);
	insert(num0,num1,num2);//插入操作 
	insert(num1,num3,num4);
	insert(num2,num5,NULL);
	prestack(num0);
	printf("\n");
	midstack(num0);
	printf("\n");
	laststack(num0);
	return 0;
}

先介绍这部分内容。

本篇完~

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-25 04:36:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-25 04:36:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-25 04:36:01       82 阅读
  4. Python语言-面向对象

    2024-01-25 04:36:01       91 阅读

热门阅读

  1. springboot切面怎么将参数修改后传给目标方法

    2024-01-25 04:36:01       53 阅读
  2. Golang 定时任务的几种实现方法

    2024-01-25 04:36:01       54 阅读
  3. C# 实现 Vigenere 密码

    2024-01-25 04:36:01       46 阅读
  4. C++拾遗(四)引用与指针

    2024-01-25 04:36:01       45 阅读
  5. ROS学习笔记10——自定义源文件调用

    2024-01-25 04:36:01       54 阅读
  6. springboot集成mybatis处理json类型

    2024-01-25 04:36:01       59 阅读
  7. 汽车数据解决方案:通过更好的数据提高速度

    2024-01-25 04:36:01       56 阅读
  8. c语言之goto语句

    2024-01-25 04:36:01       57 阅读
  9. 数据结构:顺序表

    2024-01-25 04:36:01       54 阅读
  10. Numpy库:常用函数

    2024-01-25 04:36:01       51 阅读