赞
踩
该程序是完全照搬视频中的代码。链接: https://www.bilibili.com/video/BV18p4y167Md?p=108.
典型的存储方式就两种,要么是顺序存储(利用数组这种机制),要么是链式存储(利用链表这种机制)。
基于二叉树区别于其他树的结构,且其最多只有两个孩子结点等特性,二叉树可以用顺序存储来实现,但这种顺序存储在空间利用率上会有一定的缺陷。
n层二叉树(或者说深度为 n 的二叉树)最多有2n - 1个结点。
使用顺序存储(利用数组)来实现满二叉树和完全二叉树是非常适合的,斜二叉树就不合适了。
实现二叉树的最基本的思想就是 “ 递归 ”
这里创建二叉树的规则如下:
与当前结点的 id 的值进行比较,若比当前结点小,就作为当前结点的左子树,如果比当前结点大,就作为当前结点的右子树。如果当前结点已经有了左子树或者右子树,就继续与它的左子树或者右子树进行比较,然后进行创建。
具体实现是:
在程序中,我们会事先把每个要创建的结点的 id 都定义在一个数组中。当然,由于第一个 id 之前没有其他的 id,无法比较,所以我们就直接把它作为根节点。当创建第二个结点的时候,就让它与根节点进行比较,然后依此进行。
示例如下:
程序中在二叉树中插入第一个结点的示意图如下:
这个程序实现了三个功能:
1、在二叉树中插入结点
2、根据 id 来查找结点
3、采用 “左倒” 的方式将二叉树给绘制出来。
程序代码如下:
目前,对于递归的思想,没有理解的很透彻
#include <stdio.h> #include <stdlib.h> #define NAMESIZE 32 struct score_st { int id; char name[NAMESIZE]; int math; int chinese; }; /* 二叉链表的基本思想:令二叉树的每个结点对应一个链表结点,链表结点除了 存放与数据信息之外,还要设置指示左右孩子的指针。 */ //二叉链表的缺点--不能够通过孩子结点来找到它的双亲 struct node_st { //数据域 struct score_st data; //指针域 struct node_st *lchild,*rchild; }; //待插入的数据 -- 要遵循一定的原则 //注意第一个参数是一个二级指针 int insert(struct node_st **root,struct score_st *data) { struct node_st *node; //当第一个结点插入进来 if(*root == NULL) { node = malloc(sizeof(*node)); if(node == NULL) return -1; node->data = *data; node->lchild = NULL; node->rchild = NULL; *root = node ; return 0; } //将要插入的这个结点的id与当前结点的id进行比较, //如果相等或者更小的话,就插入到左子树, //否则就插入到右子树。 if(data->id <= (*root)->data.id)//'.'用于结构体变量访问成员,->用于结构体指针访问成员 return insert(&(*root)->lchild,data); return insert(&(*root)->rchild,data); } void print_s(struct score_st *data) { printf("%d %s %d %d.\n",data->id,data->name,data->math,data->chinese); } struct score_st *find(struct node_st *root,int id) { if(root == NULL) return NULL; if(id == root->data.id) return &root->data; if(id < root->data.id) return find(root->lchild,id); else return find(root->rchild,id); } //struct node_st *root -- 当前结点 //level -- 当前结点所在的层数 void draw_(struct node_st *root,int level) { int i; //如果当前结点为叶子结点 if(root == NULL) return; //父结点的右子树 -- 右子树位于它的父结点的下一层 draw_(root->rchild,level+1); for(i=0;i<level;i++) printf(" "); //父结点 print_s(&root->data); //左子树 -- 左子树位于它的父结点的下一层 draw_(root->lchild,level+1); } void draw(struct node_st *root) { //画图采用向左倒的方式 /* C A 左倒 / / \ ---> A B C \ B */ // 画出这样的一棵树需要有两个要素:1、要分清楚当前结点的左右子树 // 2、还要进行计数,得到当前数的度(层数),方便计算出空格数 draw_(root,0);//从这棵树的第一层,即根节点开始 } int main() { int i; int arr[] = {1,2,3,7,6,5,9,8,4}; //一说到链式存储,就要反应到要不要有头结点 //这里,头结点没有什么必要。 //创建一颗空树 struct node_st *tree = NULL; //我要想调用insert的话,首先把每个结点的数据结构给做出来 struct score_st tmp,*find_result; //我们要使用insert函数将这棵树给构建起来 for(i=0;i < sizeof(arr)/sizeof(*arr);i++) { tmp.id = arr[i]; snprintf(tmp.name,NAMESIZE,"stu%d",arr[i]); tmp.math = rand()%100; tmp.chinese = rand()%100; //这棵数由于是不带头结点的,所以起始位置会变化,所以应该传入的是这棵树的地址过去. insert(&tree,&tmp); } //把这棵树给绘制出来 draw(tree); //这里将查找的测试代码给注释了 #if 0 //我要来查找有没有id为2的那个人 int tmpid = 2; //我希望在这棵树中查找一个指定的id find_result = find(tree,tmpid); if(find_result == NULL) printf("Can not find the id %d . \n",tmpid); else print_s(find_result); return 0; #endif }
对于该程序的递归调用参考
https://www.bilibili.com/video/BV1ze411x7x8.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。