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

长春网站建设模板样式做视频找素材的网站有哪些

长春网站建设模板样式,做视频找素材的网站有哪些,新做好的网站如何做seo,做旅游的网站在哪里做目录 1前置说明 2.二叉树的遍历 2.1前序、中序、后序遍历 2.2层序遍历 3.节点个数 4.树的高度(根节点的高度为1) 5.树的第K层的节点个数 (层数大于0) 6.查找 7.判别完全二叉树 8.销毁二叉树 9.创建二叉树 1前置说明 下文将链式二叉树简称为二叉树 学习二叉树首先需…

目录

1前置说明

2.二叉树的遍历

2.1前序、中序、后序遍历

 2.2层序遍历

 3.节点个数

4.树的高度(根节点的高度为1) 

5.树的第K层的节点个数 (层数大于0)

6.查找 

7.判别完全二叉树

8.销毁二叉树

9.创建二叉树 


1前置说明

下文将链式二叉树简称为二叉树

学习二叉树首先需要创建一棵二叉树,但初学者直接学习二叉树的创建方式,难度可谓是从入门到入土,所以下面先手动创建一棵二叉树,了解二叉树的部分操作后再回过头来研究二叉树真正的创建方式

typedef int BTDataType;
typedef struct BinaryTreeNode
{struct BinaryTreeNode* left;struct BinaryTreeNode* right;BTDataType val;}BTNode;BTNode* BuyBTNode(BTDataType val)
{BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (!root){perror("malloc fail");return NULL;}root->left = NULL;root->right = NULL;root->val = val;return root;
}BTNode* CreateBinaryTree()
{BTNode* node1 = BuyBTNode(1);BTNode* node2 = BuyBTNode(2);BTNode* node3 = BuyBTNode(3);BTNode* node4 = BuyBTNode(4);BTNode* node5 = BuyBTNode(5);BTNode* node6 = BuyBTNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}

 (1)上述代码重命名了 int 类型,方便后续更改数据类型

(2)一棵二叉树的一个节点包含:储存变量val,左右孩子节点指针left、right

(3)BuyBTNode函数在堆上开辟空间,并初始化每个节点

(4)CreateBinaryTree函数手动创建了一棵二叉树,并返回根节点指针。如下图:

2.二叉树的遍历

2.1前序、中序、后序遍历

1. 前序遍历(先序遍历、先根遍历)——访问根结点的操作发生在遍历其左右子树之前

根 左子树 右子树

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

左子树 根 右子树

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

左子树 右子树 根

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

//根 左 右
void PrevOrder(BTNode* root){if (!root){printf("NULL ");return;}printf("%d ", root->val);PrevOrder(root->left);PrevOrder(root->right);
}
// 左 根 右
void InOrder(BTNode* root){if (!root){printf("NULL ");return;}InOrder(root->left);printf("%d ", root->val);InOrder(root->right);
}
// 左 右 根
void PostOrder(BTNode* root){if (!root){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->val);
}

三种遍历实现方式及运行结果如上

前序遍历为例,下面通过递归展开图,更好体会遍历的过程 

如上图

调用PrevOrder函数并传入根节点(节点存储值为1)的指针,指针不为空,打印节点值,然后递归调用PrevOrder函数访问根节点的左子树(节点存储值为2),指针不为空,打印节点值,然后递归调用PrevOrder函数访问当前节点的左子树(节点存储值为3),指针不为空,打印节点值,然后递归调用PrevOrder函数访问当前节点的左子树,指针为空,函数返回,开始访问值为3的节点的右子树,指针为空,函数返回,开始访问值为2的节点的右孩子,指针为空,函数返回,开始访问值为1的节点的右子树,.........

 上诉过程中,打印节点值、函数返回就是遍历访问节点的一种方式

首先访问根节点,然后是根节点的左子树,左子树又是由根、左子树、右子树构成的,所以先访问根,再访问根的左子树的左子树,左子树又是由根、左子树、右子树构成的,所以先访问根,再访问根的左子树的左子树的左子树,此时为空树,该方向的遍历停止,开始访问根的左子树的左子树的右子树,此时为空树,该方向的遍历停止,开始访问根的左子树的右子树,此时为空树,该方向的遍历停止,开始访问根的右子树...........

前中后序的遍历落实到了递归上,可根据下图再理解理解

三种遍历的本质差异在于访问根节点的时机

 2.2层序遍历

 顾名思义,层序遍历就是一层一层的访问二叉树的节点(先第一层,再第二层......)

这里需要用到前面队列的特性,首先树为空直接返回,否则,从根节点开始,将节点的指针

(不为空)入队,然后在出队的同时,将该节点的左右孩子节点入队,队列为空时就停止 

如上图所示,(以节点存储值代替节点指针说明)

1入队,1出队,同时2、4入队;2出队,同时3入队(2的右孩子为空,没必要入队);4出队,同时5、6入队;3出队(左右孩子为空,没必要入队),5出队(左右孩子为空,没必要入队),6出队(左右孩子为空,没必要入队),停止

void LevelOrder(BTNode* root){if (!root)return;Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* Front = QueueFront(&q);QueuePop(&q);//if (Front)  //第一次插入的树节点指针不为空//第一次可以放心打印,后续控制不进空,就直接打印printf("%d ", Front->val);//空没有必要进,if (Front->left)QueuePush(&q, Front->left);if (Front->right)QueuePush(&q, Front->right);}QueueDestroy(&q);}

 (1)树为空,直接返回,否则初始化队列,并将根节点指针入队

(2)调用QueueFront函数拿到队首元素中存储的节点指针值,

然后出队,同时代入其不为空的孩子节点

(3)队列为空时停止,注意销毁队列,防止内存泄漏

 3.节点个数

//左 + 右 + 1
int TreeSize(BTNode* root){if (!root)return 0;return TreeSize(root->left) + TreeSize(root->right) + 1;
}

代码非常简洁,意思就是节点为空返回0,否则该棵树的节点个数等于

左子树的节点个数 + 右子树的节点个数 + 1

 如上图

调用TreeSize函数并传入根节点(节点存储值为1)的指针,指针不为空,调用TreeSize函数计算节点(节点存储值为1)的左子树(根节点存储值为2)的节点个数,指针不为空,调用TreeSize函数计算节点(节点存储值为2)的左子树(根节点存储值为3)的节点个数,指针不为空,调用TreeSize函数计算节点(节点存储值为3)的左子树的节点个数,指针为空,函数返回0,开始计算节点存储值为3的节点的右子树的节点个数,指针为空,函数返回0,开始计算值为2的节点的右子树的节点个数,指针为空,函数返回0,开始计算值为1的节点的右子树的节点个数,.........

总结来说,这又是一次递归实战,重要的是求出递推公式,找到最小子问题及其结束条件

对于本题来说, 

递推公式: 

该棵树的节点个数等于左子树的节点个数 + 右子树的节点个数 + 1

最小子问题及其结束条件:

对于某一个节点,为空就返回0,不为空就套用递推公式

4.树的高度(根节点的高度为1) 

//左右子树较高者 + 1
int TreeHeight(BTNode* root){if (!root)return 0;int l = TreeHeight(root->left);int r = TreeHeight(root->right);return l > r ? l + 1 : r + 1;
}

同样是递归实战,递推公式: 树高 = 左右子树较高者的高度 + 1

最小子问题及其结束条件:树为空就返回0,否则先分别计算左右子树的高度,再比较返回

以节点存储值代替节点指针进行说明

1不为空,先计算1的左子树(根节点存储值为2)的高度,2不为空,先计算2的左子树(根节点存储值为3)的高度,3不为空,先计算3的左子树的高度,树为空,返回0,再计算3的右子树的高度,树为空,返回0,比较返回1,(即2的左子树(根节点存储值为3)的高度),再计算2的右子树的高度,树为空,返回0,比较返回2,(即1的左子树(根节点存储值为2)的高度),此时该树的左子树的高度计算完毕,开始计算其右子树的高度..........

5.树的第K层的节点个数 (层数大于0)

//左右子树第K - 1 层的节点个数之和
int TreeKLevel(BTNode* root, int k){assert(k > 0);if (!root)return 0;if (k == 1)return 1;return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}

递推公式: 树的第K层节点个数 = 左子树第 K - 1 层节点个数 + 右子树第 K - 1 层节点个数

最小子问题及其结束条件:对于某一节点,为空就返回0,不为空且所在层数(设为w)为1就返回1,否则需分别计算其左右子树第1+k - w层(不用手动计算,递归调用时,层数自动递减)的节点个数,再求和

以节点存储值代替节点指针进行说明

1不为空,先计算1的左子树(根节点存储值为2)第2层的节点个数,2不为空,先计算2的左子树(根节点存储值为3)第1层的节点个数,3不为空且层数为1,返回1,再计算2的右子树的第1层的节点个数,树为空,返回0,求和返回得到1的左子树的第2层的节点个数,此时该树的左子树的第2层的节点个数计算完毕,开始计算其右子树的第2层的节点个数..........

6.查找 

// 自己 左右子树中找
BTNode* BinaryTreeFind(BTNode* root, BTDataType x){if (!root)return NULL;if (root->val == x)return root;BTNode* left = BinaryTreeFind(root->left, x);if (left)return left;BTNode* right = BinaryTreeFind(root->right, x);if (right)return right;return NULL;
}

在普通二叉树中查找某个值的思路:先在当前节点找,再到左右子树去找

最小子问题及结束条件就是,对于某一节点,如果为空,返回空,如果所存储值就是要找的值就返回该节点的指针,否则再去它的左右子树找,找不到就返回空 

7.判别完全二叉树

层序遍历二叉树的节点指针(空树NULL也算),可以发现

完全二叉树层序遍历的特点:不为空的节点指针连续

普通二叉树层序遍历的特点:为空的节点指针不连续

bool BinaryTreeComplete(BTNode* root)
{if (!root)return true;//首先入队Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* Front = QueueFront(&q);QueuePop(&q);//空也入队if (Front){QueuePush(&q, Front->left);QueuePush(&q, Front->right);}else{break;}}//完全二叉树的空是连续的!!while (!QueueEmpty(&q)){if (QueueFront(&q)){//注意资源清理QueueDestroy(&q);return false;}QueuePop(&q);}QueueDestroy(&q);return true;
}

 (1)树为空,返回真,否则根节点指针入队

(2)取得队首元素的节点存储值,出队,然后代入该节点的左右孩子(如果有的话)

(3)没有左右孩子,说明遇到了第一个NULL节点,此时选择跳出循环,遍历队列中剩下的元素,如果存在队首元素的节点存储值不为空,返回false,并及时清理队列资源,遍历完成则意味着该树是完全二叉树,返回true,并及时清理队列资源

8.销毁二叉树

销毁一棵二叉树,第一想法就是遍历销毁,可选择哪种遍历方式呢?

先序遍历,直接就把根节点给销毁了,需要提前保存左右孩子节点

中序遍历,根节点会先于右孩子节点销毁了,需要提前保存右孩子节点

所以选择后序遍历,先销毁孩子节点再销毁根而无需提前保存孩子节点

void BinaryTreeDestory(BTNode** root)
{//root一定不为空assert(root);if (!(*root))return;BinaryTreeDestory(&((*root)->_left));BinaryTreeDestory(&((*root)->_right));free(*root);*root = NULL;
}

最小子问题及其结束条件:节点为空即返回,否则先销毁它的孩子节点,再销毁自己 

9.创建二叉树 

通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

思路:遍历字符数组,遇到'#'(意味着空节点)就返回,否则就开辟一个节点的空间存储该值,

并用下一个字符所在的节点作为上一个字符所在节点的左孩子,......直到遇见'#',左孩子方向创建完毕,开始创建右孩子节点

BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{if (a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));root->_data = a[(*pi)++];root->_left = BinaryTreeCreate(a, pi);root->_right = BinaryTreeCreate(a, pi);return root;
}

(1)下标 i 遍历数组,需要传入它的地址使其按需改变

(2)思路就是按照先序遍历的顺序,先创建根节点,再创建根节点的左孩子,左孩子是一棵子树的根节点,所以再创建根节点的左孩子的左孩子,......直到为空,开始创建右孩子节点....

http://www.dtcms.com/wzjs/810622.html

相关文章:

  • 网站建设费用报价网站建设公司华网天下北京
  • idea做网站登录厦门网站建设工程
  • 山西通州集团网站建设国际进出口贸易网站
  • 网站建设 数据归属微信平台可以做微网站吗
  • 大连投诉网站网页升级访问最新区域每天自动更新
  • 无忧网站优化淘宝店招图片大全免费
  • 做网站编辑需要看什么书全网营销的四大优势
  • 集团网站建设报价企业局域网做网站屏蔽
  • 信阳网站建设找汉狮百度小说风云榜排名
  • 网站建设 域名 数据库济南品牌网站建设定制
  • 海城建设网站wordpress国外vps
  • 中国优秀设计网站有哪些福田企业网站建设
  • 芜湖手机网站开发什么是平面设计 都包括哪些内容
  • 个人开发的软件能卖吗网站优化和推广
  • 河南省住房和城乡建设局网站长沙网络公司营销推广
  • 铜仁网站网站建设青海网站建设的企业
  • 云畅网站建设国内最大ae模板下载网站
  • 门户网站 建设企业网站备案
  • wordpress 双语站点拓者设计吧手机版
  • 网站开发的前端与后端如何加快百度收录网站
  • 南通门户网站世界杯直播入口官网
  • 掼蛋网站建设项目管理工具
  • 永州建设公司网站wordpress的用户名密码
  • 建立网站需要多少钱怎么样国内最大的搜索引擎
  • 广州营销型网站建设团队抚顺市+网站建设
  • 北京+网站建设中国科技成就作文800字
  • 网页给别人做的 网站后续收费杭州搜索推广公司
  • 该网站正在建设html5制作网页的步骤
  • 撰写网站栏目规划网站的建设特色
  • 网站友情链接自动上链移动网站建站