当前位置: 首页 > wzjs >正文

wordpress about页面互联网优化

wordpress about页面,互联网优化,国家企业信用信息公示系统登录,重庆简易注销在什么网站做前两篇文章我们讲解了顺序结构的二叉树 -- 堆以及堆的应用堆排序,所以这篇文章我们来讲解一下二叉树的链式结构 -- 链式二叉树。 目录 1 链式二叉树的结构 2 二叉树的遍历 1) 前序遍历 (1) 遍历规则 (2&#xf…

  前两篇文章我们讲解了顺序结构的二叉树 -- 堆以及堆的应用堆排序,所以这篇文章我们来讲解一下二叉树的链式结构 -- 链式二叉树。


目录

1  链式二叉树的结构

2  二叉树的遍历

1) 前序遍历

(1) 遍历规则

(2) 代码实现

2) 中序遍历

(1) 遍历规则

(2) 代码实现

3) 后序遍历

(1) 遍历规则

(2) 代码实现

4) 层序遍历

(1) 遍历规则

(2) 代码实现

3  链式二叉树的实现 

1) 求二叉树节点的个数

 2) 二叉树叶子节点的个数

3) 二叉树第 k 层节点个数

4) 二叉树的高度/深度

5) 二叉树中查找值为 x 的节点

6) 二叉树的销毁

7) 判断一棵树是否是完全二叉树

8) 代码


重点一  链式二叉树的结构

1  链式二叉树的结构

  链式二叉树是用链式结构实现的二叉树,所以二叉树是由一个一个节点组成的,节点与节点之间用指针连接起来就形成了一棵二叉树。所以要定义链式二叉树的结构,主要就是要定义节点的结构,由于每个节点有左孩子也有右孩子,所以节点结构里面肯定要有两个指向左孩子和右孩子的指针域,另外,由于每个节点里面又有数据,所以节点结构里面还需要有一个存储数据的数据域

typedef int BTDataType;
//链式树的结构
typedef struct BinTreeNode
{BTDataType data;//二叉树结点里面的数据struct BinTreeNode* left;//左孩子指针struct BinTreeNode* right;//右孩子指针
}BTNode;

2  二叉树的遍历

  所谓遍历,就是将二叉树中所有节点的值都访问一遍,然后将访问的值按照一定序列输出出来。对于二叉树的遍历总共有四种方式:前序遍历,中序遍历,后序遍历以及层序遍历,其中前序遍历,中序遍历和后序遍历就是深度优先遍历,层序遍历就是广度有限遍历。

1) 前序遍历

(1) 遍历规则

  前序遍历就是先访问一棵子树的根,然后再访问该节点的左子树,在其左子树里,再先访问根节点,然后访问左子树,依次类推,直到访问到空,然后回溯到最近的根节点,再访问其右子树,在其右子树里再按根左右的方式遍历整棵数,依次类推,如下面这棵二叉树:

其走前序遍历的过程为:首先从根节点出发,先访问根节点10,之后去访问其左子树,在左子树里又先访问根节点14,然后再去14的左子树里访问29根节点,之后再去29的左子树里访问22根节点,然后22去访问其左子树的根节点,由于是空,所以直接返回到22这个根节点,之后再去22根节点的右子树去访问根节点,由于是空,所以返回到22根节点,之后以22左为根节点的整棵子树全都访问结束,再向上回溯到 29 根节点,去访问29的右子树,之后的过程依次类推,所以这棵树先序遍历的过程为:

蓝色的为先后访问的序号,所以这棵树先序遍历的序列为:10, 14, 29, 22, 11, 15, 28, 9, 12, 9, 11

(2) 代码实现

  由于整棵二叉树是递归定义的,所以我们也采取递归的算法来实现二叉树的前序遍历。这里给前序遍历的函数取名为 PreOrder,参数仅有一个就是二叉树节点的指针 root 表示一棵二叉树的根节点。递归算法最重要的就是实现定义边界条件。这里的边界条件就是当二叉树遍历到 NULL 的时候,我们就应该退出递归了,NULL 节点代表里面没有实际值,所以也就不需要遍历该节点,然后按照前序遍历 根左右 的过程写出代码即可:

//BTNode为链式二叉树的节点
void PreOrder(BTNode* root)
{if (root == NULL){return;}printf("%d ", root->data);//先输出根节点信息PreOrder(root->left);//再遍历根节点的左子树PreOrder(root->right);//再遍历根节点的右子树
}

我们来看一下其递归的过程:
 

2) 中序遍历

(1) 遍历规则

  中序遍历就是先访问一棵树的左子树,然后访问根,再访问另一棵树的右子树,按照左根右的方式去遍历一整棵树,如下面这棵树:

其走中序遍历的过程为:先访问 21 根节点的左子树,然后再去访问 11 根节点的左子树,再访问 19 根节点的左子树,之后访问完 5 之后,输出 5 ,然后回溯到 19 根节点,然后输出 19 ,再去访问 19 根节点的右子树,然后再回溯到根 19,以 19 作为根节点的整棵子树访问完成,之后回溯到 11 该根节点,输出 11,然后再去访问 11 根节点的右子树,依次类推。其边的遍历过程与前序遍历相同,但是输出序列不同,这棵树走中序遍历的序列为:5, 19, 39, 11, 30, 21, 50, 25, 1, 32, 29, 17(前序遍历为:21, 11, 19, 5, 39, 30, 32, 25, 50, 1, 29, 17)。

(2) 代码实现

  其实中序遍历的代码与前序遍历类似,只不过是访问根节点顺序变了:

//BTNode为链式二叉树的节点
void InOrder(BTNode* root)
{if (root == NULL){return;}PreOrder(root->left);//先遍历根节点的左子树printf("%d ", root->data);//再输出根节点信息PreOrder(root->right);//再遍历根节点的右子树
}

3) 后序遍历

(1) 遍历规则

  后序遍历就是先访问一棵树的左子树,然后访问其右子树,最后访问根,按照左右根的方式遍历整棵树,如下面这棵树:

其走后序遍历的过程为: 先去访问 21 根节点的左子树,之后再去访问 11 根节点的左子树,再去访问 19 根节点的左子树,由于左子树只有一个节点,所以会输出 5,之后访问 19 根节点的右子树,输出 39,回溯到 19 根节点,输出 19,之后回溯到 11 根节点,再去访问其右子树 30,输出30,然后回溯到 11 根节点,输出 11,依次类推。所以这棵二叉树走后序遍历的序列为:5, 39, 19, 30, 11, 50, 1, 25, 17, 29, 32, 21

(2) 代码实现

  后序遍历也类似于前序遍历和中序遍历代码逻辑,只要把输出根节点信息的顺序改变一下就可以了:

//BTNode为链式二叉树的节点
void PostOrder(BTNode* root)
{if (root == NULL){return;}PreOrder(root->left);//先遍历根节点的左子树PreOrder(root->right);//再遍历根节点的右子树printf("%d ", root->data);//最后输出根节点信息
}

4) 层序遍历

(1) 遍历规则

  层序遍历,也是二叉树里的广度优先遍历,就是按照二叉树的层次由第一层到第 k 层的顺序依次遍历每个节点,在每层里又会按照从左至右的顺序依次遍历。如下面这棵树进行层次遍历的过程为:

先走第一层(也就是整棵二叉树的根节点一层)21,输出21,再从左至右遍历第二层,输出11,32,依次类推。所以,整棵二叉树进行层序遍历的序列为:21, 11, 32, 19, 30, 25, 29, 5, 39, 50, 1, 17。 

(2) 代码实现

  实现二叉树的层序遍历需要借助一个数据结构队列队列的每个节点里面存储的不再是整型,而是链式二叉树的每个节点的指针。先让根节点入队,然后输出其节点里存储的数据,如果根节点左子树不为空,那就让其左孩子入队,如果右孩子不为空,再让右孩子入队,然后让根节点出队,依次类推,直到队列为空为止,实现过程如图:

代码:

//Queue里面应该是 typedef BTNode* QDataType;
void LevelOrder(BTNode* root)
{assert(root);//借助队列Queue q;QueueInit(&q);//先让根节点入队QueuePush(&q, root);//循环判断队列是否为空while (!QueueEmpty(&q)){BTNode* pop = QueueFront(&q);//输出队头元素printf("%d ", pop->data);//队头元素出队QueuePop(&q);//左孩子不为空,让左孩子入队if (pop->left){QueuePush(&q, pop->left);}if (pop->right){QueuePush(&q, pop->right);}}//不要忘记销毁队列QueueDestroy(&q);
}

3  链式二叉树的实现 

  对于链式二叉树,除了以上的四种遍历,还有其他操作需要实现,分别包括求二叉树节点个数、二叉树叶子节点的个数、二叉树第k层节点个数、二叉树的深度/高度、二叉树查找值为 x 的节点、二叉树的销毁和判断一棵树是否是完全二叉树

  可以看到在链式二叉树里面并没有二叉树的初始化与插入和删除节点,因为对于一棵普通二叉树来说,其插入节点的限制太少了,导致插入在哪个节点的左右孩子上都可以,所以这里并不涉及普通二叉树的插入和删除节点,以后在 AVL 树(二叉平衡树)以及红黑树里面会有相应的插入与删除节点的操作。

1) 求二叉树节点的个数

  求二叉树节点的个数可以采用递归算法来解决。我们可以这样想,对于一棵二叉树来说,其节点个数就等于根节点个数(也就是1个)加上左子树节点个数和右子树节点个数。那么边界条件就是当一个节点为NULL时,代表这个节点并不是一个有效节点,所以返回0就可以了

 2) 二叉树叶子节点的个数

  找叶子节点的个数同样可以采用递归算法来解决。整棵树的叶子节点的个数就等于根节点的左子树中叶子结点的个数 + 右子树中叶子节点的个数。这个操作的边界条件有两个,一个是如果节点为NULL,代表没有节点了,返回0;另一个是找到了一个叶子结点(root->left == NULL && root->right == NULL),就返回1。

3) 二叉树第 k 层节点个数

  该操作也可以通过递归算法来解决。求第 k 层节点个数可以拆解为求左子树第 k - 1层节点个数 + 右子树第 k - 1层节点个数边界条件也有两个,一个是节点为NULL时,返回0;另一个是如果 k 变为了1, 那么就需要返回 1。

4) 二叉树的高度/深度

   同样的,该操作也是使用递归算法来解决。整棵二叉树的高度可以想成是根节点的高度(也就是1)加上左子树与右子树的高度的较大值。所以返回是是左子树与右子树高度中的较大者。边界条件就是当节点为 NULL 时,代表该节点并不是一个有效节点,所以返回 0 就可以了。

5) 二叉树中查找值为 x 的节点

  类似于上面几个操作,该操作也是利用递归算法来解决问题。该问题可以变成先看根节点的值是否是 x ,如果不是那就去左子树里面查找值为 x 的节点,如果左子树也没有,那就去右子树查找值为 x 的节点。要注意的是,查找值为 x 的节点只需要返回一个节点就可以了,返回只要找到一个节点值为 x 就要结束递归,返回该节点了。边界条件共有3个,一个就是如果节点为 NULL 了,说明不是有效节点,就返回 NULL;还有一个就是如果根节点值为 x 了,就说明找到了一个值为 x 的节点了,直接返回根节点;第三个就是如果在根节点与左子树和右子树内都没有找到值为 x 的节点,也需要返回 NULL 。

6) 二叉树的销毁

  销毁呢,同样可以采用递归算法来解决。销毁整棵二叉树可以看作是先销毁左子树,再销毁右子树,最后销毁根节点。要注意的是必须先销毁根节点的左子树或者右子树,才能销毁根节点,因为先销毁根节点的话,那么其左右子树就找不到了,会造成内存泄露的。边界条件就是当节点为 NULL 时,该节点不需要销毁,直接返回就可以了。

7) 判断一棵树是否是完全二叉树

  要判断一棵树是否是完全二叉树,我们需要从完全二叉树的特点出发,下面是一棵完全二叉树:

我们可以看到完全二叉树的特点就是在一层里节点都是从左至右依次排列的,且除了最后一层,上面的每层节点都是满的。所以从这个特性出发,我们可以看到如果对一棵完全二叉树进行层序遍历,在出现NULL节点之后,后面的节点一定都是空节点,所以判断一棵二叉树是否是完全二叉树的算法就可以这样设计:
  借助辅助数据结构队列,先对一棵树进行层序遍历,但注意的是,如果某个节点的孩子节点是空,也要让其入队,之后循环取对头元素,让其左右孩子入队,让队头元素出队,直到队列为空或者队头元素为NULL;之后再判断队列是否为空,再次取对头,判断队头元素是否有非空节点,如果,那就不是一棵完全二叉树,如果没有,那就是一棵完全二叉树。该算法的执行过程如下:
 


8) 代码

BinaryTree.h文件:

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;//前序遍历
void PreOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后序遍历
void PostOrder(BTNode* root);
//层序遍历
void LevelOrder(BTNode* root);
//二叉树结点个数
int BTSize(BTNode* root);
//二叉树叶子结点个数
int BTLeafSize(BTNode* root);
//二叉树第k层的结点个数
int BTLevelkSize(BTNode* root, int k);
//二叉树的深度
int BTLevel(BTNode* root);
//二叉树查找值为x的结点
BTNode* BTFind(BTNode* root, int x);
//二叉树销毁
//这里要传二级指针,因为根节点也要销毁,销毁之后实参要置为NULL
void BTDestroy(BTNode** root);
//判断是否为完全二叉树
bool BTComplete(BTNode* root);

BinaryTree.c文件:

#include"BinaryTree.h"//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){return;}//根 -- 左 -- 右printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){return;}//左 -- 根 -- 右InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}//后序遍历
void PostOrder(BTNode* root)
{if (root == NULL){return;}//左 -- 右 -- 根PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}//二叉树结点个数
//根结点个数加上左子树结点个数加上右子树结点个数
int BTSize(BTNode* root)
{if (root == NULL){return 0;}return 1 + BTSize(root->left) + BTSize(root->right);
}//二叉树叶子结点个数
//左子树的叶子结点个数加上右子树的结点个数
int BTLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){//找到了一个叶子结点return 1;}//返回左右孩子叶子结点个数return BTLeafSize(root->left) + BTLeafSize(root->right);
}//二叉树第k层的结点个数
int BTLevelkSize(BTNode* root, int k)
{if (root == NULL){return 0;}//如果k为1,返回1if (k == 1){return 1;}//返回左子树第k层结点个数 + 右子树第k层结点个数return BTLevelkSize(root->left, k-1) + BTLevelkSize(root->right, k-1);
}//二叉树的深度
int BTLevel(BTNode* root)
{if (root == NULL){return 0;}//返回左子树与右子树深度最大的深度+根结点深度int leftdep = BTLevel(root->left);int rightdep = BTLevel(root->right);return 1 + (leftdep > rightdep ? leftdep : rightdep);
}//二叉树查找值为x的结点
BTNode* BTFind(BTNode* root, int x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}//如果查找的左孩子不为空,返回左孩子查找的结点BTNode* leftfind = BTFind(root->left, x);if (leftfind){return leftfind;}//如果查找的右孩子不为空,返回右孩子查找的结点BTNode* rightfind = BTFind(root->right, x);if (rightfind){return rightfind;}//如果查找不到,返回NULLreturn NULL;
}//二叉树销毁
void BTDestroy(BTNode** root)
{if (*root == NULL){return;}BTDestroy(&(*root)->left);BTDestroy(&(*root)->right);free(*root);*root == NULL;
}//判断是否为完全二叉树
//要借助辅助数据结构队列
bool BTComplete(BTNode* root)
{Queue q;QueueInit(&q);//让根结点入队QueuePush(&q, root);//如果队列不为空,或者遇到了NULL结点,那就结束循环while (!QueueEmpty(&q)){//取队头,出队头BTNode* top = QueueFront(&q);QueuePop(&q);if (top == NULL){break;}//让结点的左右孩子都入队,不管为不为NULLQueuePush(&q, top->left);QueuePush(&q, top->right);}//判断队列为不为空,如果里面节点有NULL,那就返回falsewhile (!QueueEmpty(&q)){BTNode* top = QueueFront(&q);if (top != NULL){QueueDestroy(&q);return false;}QueuePop(&q);}//如果队列没有遇到NULL结点QueueDestroy(&q);return true;
}//层序遍历
//需要借助辅助数据结构队列
void LevelOrder(BTNode* root)
{//队列不能为空assert(root);//先初始化一个队列Queue q;QueueInit(&q);//然后让根节点入队QueuePush(&q, root);while (!QueueEmpty(&q)){//取队头元素BTNode* top = QueueFront(&q);//打印数据printf("%d ", top->data);//让头节点出队QueuePop(&q);//如果左孩子不为空,就让左孩子入队if (top->left){QueuePush(&q, top->left);}//如果右孩子不为空,就让右孩子入队if (top->right){QueuePush(&q, top->right);}}//销毁队列QueueDestroy(&q);
}

test.c文件:

我们选择手动创建这么一颗树

test.c文件:
 

#include"BinaryTree.h"BTNode*  buyNode(BTDataType x)
{BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("malloc fail!\n");exit(1);}root->data = x;root->left = root->right = NULL;return root;
}
//创建一颗链式二叉树
BTNode* CreateTree()
{BTNode* node1 = buyNode(1);BTNode* node2 = buyNode(2);BTNode* node3 = buyNode(3);BTNode* node4 = buyNode(4);BTNode* node5 = buyNode(5);BTNode* node6 = buyNode(6);BTNode* node7 = buyNode(7);//接下来改变左孩子指针与右孩子指针指向,使其成为一棵树node1->left = node2;node1->right = node3;node2->left = node4;node3->left = node5;node4->right = node6;return node1;
}
void Test()
{BTNode* root = CreateTree();//测试前序遍历//1  2  4  6  3  5//PreOrder(root);//测试中序遍历//4  6  2  1  5  3//InOrder(root);//测试后序遍历//6  4  2  5  3  1//PostOrder(root);//测试层序遍历//1  2  3  4  5  6//LevelOrder(root);//测试结点个数//6/*int size = BTSize(root);printf("%d ", size);*///测试叶子结点个数//2//int size = BTLeafSize(root);//printf("%d ", size);//测试第k层结点个数/*int size = BTLevelkSize(root, 4);printf("%d ", size);*///测试二叉树的深度//int depth = BTLevel(root);//printf("%d ", depth);//测试查找/*BTNode* ret = BTFind(root, 7);if (ret == NULL){printf("找不到!\n");}elseprintf("%d ", ret->data);*///测试是否是完全二叉树bool ret = BTComplete(root);if (ret){printf("是完全二叉树");}else{printf("不是完全二叉树");}
}
int main()
{Test();return 0;
}

 大家可以测试一下,如果把CreateTree函数改为以下代码,看看是不是一棵完全二叉树:

BTNode* CreateTree()
{BTNode* node1 = buyNode(1);BTNode* node2 = buyNode(2);BTNode* node3 = buyNode(3);BTNode* node4 = buyNode(4);BTNode* node5 = buyNode(5);BTNode* node6 = buyNode(6);BTNode* node7 = buyNode(7);//接下来改变左孩子指针与右孩子指针指向,使其成为一棵树node1->left = node2;node1->right = node3;node2->left = node4;node3->left = node5;node2->right = node6;return node1;
}
http://www.dtcms.com/wzjs/259643.html

相关文章:

  • 做企业网站备案都需要什么英雄联盟最新赛事
  • 东莞网站建设 信科网络百度快照优化公司
  • 功能性的网站网络广告营销的案例
  • 网站开发设计流程图列举常见的网络营销工具
  • 做兼职的那个网站靠谱吗seo优化推广技巧
  • 微信做单子的网站源码百度账号登录入口网页版
  • 做油和米的网站实体店100个营销策略
  • 做图片视频的网站模板建网站价格
  • 东莞专业网站设计平台网络广告策划
  • 营销型网站制作多少钱色盲怎么治疗
  • 做游戏破解版的网站网站优化网
  • 网站开发试题库怎么seo关键词优化排名
  • 和平天津网站建设广东网站seo
  • 个人网站 cms百度反馈中心
  • 做网站服务器一年多少钱互联网营销课程体系
  • 网站改版协议seo学徒招聘
  • 网站建设与管理知识点网络营销的工作内容包括哪些
  • 宁夏小蚁人网站建设快速seo关键词优化技巧
  • 武汉网站关键词排名肇庆seo按天计费
  • 马可波罗网站做外贸无货源电商怎么做
  • 网站seo快排软件黄页推广引流网站
  • 三合一网站建设方案搜索排名查询
  • 一个备案可以做几个网站百度权重是怎么来的
  • 企业建立网站需要提供什么2023新闻摘抄大全
  • 小豹子韬韬是哪个网站做的爱网站关键词查询工具长尾
  • 电子商务网站软件建设的广告推广营销网站
  • 二道江网站建设seo策略分析
  • 云游戏免费平台seo基础教程使用
  • 安徽网站开发培训做手机关键词快速排名软件
  • 骏域网站建设专家百度网盘网页版登录入口