链式结构二叉树的遍历(前序,中序,后序及层序遍历)及基本操作

链式结构二叉树节点的定义

对链式结构二叉树进行操作,首先要创建二叉树节点,这里定义一个包含节点数据,左孩子节点,右孩子节点的结构体作为节点,之后的操作都使用这个结构体。代码如下:

typedef int BTDateType;
typedef struct BinaryTreeNode
{
  BTDateType date;
  struct BTNode*left;
  struct BTNode*right;
}BTNode;

二叉树的遍历

学习二叉树的结构,最简单的办法就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树的节点进行相应的操作,并且每个节点都只操作一次。访问节点所作的操作取决于具体的应用问题。遍历是二叉树操作中最重要的操作,也是其它操作的基础。

 按照规则,二叉树的遍历有:二叉树的前序/中序/后序的递归结构遍历。

1. 前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右子树之前。

2. 中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中(间)。

3. 后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

前序遍历

前序遍历的遍历顺序是:根节点->左子树->右子树。递归进行。

前序遍历的递归图解:

代码如下:

void BinaryPrevOrder(BTNode*root)
{
  if(root==NULL)
  {
    return;
  }
  printf("%d",root->date);
  BinaryPrevOrder(root->left);
  BinaryPrevOrder(root->right);
}

中序遍历

中序遍历的遍历顺序是:左子树->根节点->右子树。递归进行。

代码如下:

​
void BinaryInOrder(BTNode*root)
{
  if(root==NULL)
  {
    return;
  }
  BinaryPrevOrder(root->left);
  printf("%d",root->date);
  BinaryPrevOrder(root->right);
}

​

后序遍历

后序遍历的遍历顺序是:左子树->右子树->根节点。递归进行。

代码如下:

​
​
void BinaryPostOrder(BTNode*root)
{
  if(root==NULL)
  {
    return;
  }
  BinaryPrevOrder(root->left);  
  BinaryPrevOrder(root->right);
  printf("%d",root->date);
}

​

​

层序遍历

除了前序遍历,中序遍历和后序遍历外,还可以对二叉树进行层序遍历。设二叉树根节点所在层为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层上的根节点,然后从左到右访问第二层的节点,接着是第三层的节点,以此类推,自上而下,自左至右的逐层访问二叉树,这种遍历方式称为层序遍历。

 基本思路:根据层序遍历的特点,可以借助队列来实现逻辑。首先将根节点入队列,将根从队头出队时,将根的左右孩子依次从队尾入队,之后反复执行这一操作,直至所有元素都出队,二叉树遍历完毕。

代码如下:


//创建队列结构
typedef BTNode QDateType;
typedef struct QListNode
{
	struct QNode* pnext;
	QDateType date;
}QNode;

typedef struct Queue
{
	QNode* front;
	QNode* rear;
}Queue;
//队列初始化
void QueueInit(Queue* q)
{
	assert(q);
	q->front = NULL;
	q->rear = NULL;
}
//销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->front;
	while (cur != NULL)
	{
		QNode* next = cur->pnext;
		free(cur);
		cur = next;
	}
	q->front = q->rear = NULL;
}
//队尾插入数据
void QueuePush(Queue* q, QDateType date)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->date = date;
	newnode->pnext = NULL;
	if (q->front == NULL)
	{
		q->front = q->rear = newnode;
	}
	else
	{
		q->rear->pnext = newnode;
		q->rear = newnode;
	}
}
//删除队头数据
void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	QNode* next = q->front->pnext;
	free(q->front);
	q->front = next;
	if (q->front = NULL)
	{
		q->rear = NULL;
	}
}

//获取队头数据
QDateType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->front->date;
}
//判断队列是否为空
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->front == NULL;
}


//层序遍历二叉树
void BinaryTreeLevelOrder(BTNode*root)
{
  Queue q;
  QueueInit(&q);
  if(root!=Null)
  {
    QueuePush(&q,root);
  }
  while(!QueueEmpty(q))
  {
    BTNode*front= QueueFront(& q);
    QueuePop(& q);
    printf("%d ", front->data);
    if(front->left)
    {
      QueuePush(&q,root->left);
    }
    if(front->right)
    {
      QueuePush(&q,root->right);
    }
  }
  QueueDestroy(&q);
}

二叉树的深度遍历(接口型)

前面的几种遍历方式,是将一颗二叉树遍历并将遍历的元素打印出来。下面介绍的接口型遍历方式是将一颗二叉树遍历,并将遍历结果保存到一个动态开辟的数组中,遍历结束后返回这个数组。

思路:
 1.首先计算二叉树中结点的个数,便于确定动态开辟的数组的大小。
 2.遍历二叉树,将遍历结果存储到数组中。
 3.返回数组

结点的个数

求解树的结点总数时:
 1.树若为空,则结点个数为0。
 2.树若不为空,则结点个数 = 左子树结点个数 + 右子树结点个数 + 1(自己)。

代码如下:

int BTNodeSize(BTNode*root)
{
  return root==NULL?0:BTNodeSize(root->left)+BTNodeSize(root->right)+1 ;
}

前序遍历

代码如下:

int BTNodeSize(BTNode*root)
{
  return root==NULL?0:BTNodeSize(root->left)+BTNodeSize(root->right)+1 ;
}
//将节点中的数据放入数组
void preorder(BTNode* root, int* arr, int* pi)
{
	if (root == NULL)
		return;
	arr[(*pi)++] = root->data;
	preorder(root->left, arr, pi);
	preorder(root->right, arr, pi);
}

//遍历
int PrevOrderTraversal(BTNode*root,int*returnSize)
{
  *returnSize=BTNodeSize(root);
  int*arr=(int*)malloc(sizeof(int)*(*returnSize));
  int i=0;
  preorder( root,  arr, &i);
  return arr;
}

 中序遍历

代码如下:

int BTNodeSize(BTNode*root)
{
  return root==NULL?0:BTNodeSize(root->left)+BTNodeSize(root->right)+1 ;
}
//将节点中的数据放入数组
void Inorder(BTNode* root, int* arr, int* pi)
{
	if (root == NULL)
		return;
    Inorder(root->left, arr, pi);
	arr[(*pi)++] = root->data;
	Inorder(root->right, arr, pi);
}

//遍历
int InOrderTraversal(BTNode*root,int*returnSize)
{
  *returnSize=BTNodeSize(root);
  int*arr=(int*)malloc(sizeof(int)*(*returnSize));
  int i=0;
  Inorder( root,  arr, &i);
  return arr;
}

后序遍历

代码如下:

int BTNodeSize(BTNode*root)
{
  return root==NULL?0:BTNodeSize(root->left)+BTNodeSize(root->right)+1 ;
}
//将节点中的数据放入数组
void Postorder(BTNode* root, int* arr, int* pi)
{
	if (root == NULL)
		return;
    Postorder(root->left, arr, pi);
	Postorder(root->right, arr, pi);
    arr[(*pi)++] = root->data;
}

//遍历
int PostOrderTraversal(BTNode*root,int*returnSize)
{
  *returnSize=BTNodeSize(root);
  int*arr=(int*)malloc(sizeof(int)*(*returnSize));
  int i=0;
  Postorder( root,  arr, &i);
  return arr;
}

二叉树的建立与销毁 

建立二叉树

这里以前序为例建立二叉树,中序,后序及层序同理,不再赘述。

BTNode*CreatTree(int*arr,int*pi)
{
  if(arr[*pi]==NULL)
  {
    (*pi)++;
    return NULL;
  }
  BTNode*root=(BTNode*)malloc(sizeof(BTNode)); 
  root->left=NULL;
  root->right=NULL;
  root->date=arr[*pi];
  (*pi)++;
  root->left=CreatTree(arr,pi);
  root->right=CreatTree(arr,pi);
  return root;
}

销毁二叉树

二叉树的销毁,与其他数据结构的销毁类似,都是一边遍历一边销毁。但是二叉树需要注意销毁结点的顺序,遍历时我们应该选用后序遍历,也就是说,销毁顺序应该为:左子树->右子树->根。
必须先将左右子树销毁,最后再销毁根结点,若先销毁根结点,那么其左右子树就无法找到,也就无法销毁了。

代码如下:

void BinaryTreeDestory(BTNode*root)
{
  if(root==NULL)
  {
    return;
  }
  BinaryTreeDestory(root->left);
  BinaryTreeDestory(root->right);
  free(root);
}


 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值