二叉树的建立教学教材

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
例:猴子选大王。
n只猴子围成一圈,顺时针方向从1到n编号。 之后从1号开始沿顺时针方向让猴子从1, 2,…,m依次报数,凡报到m的猴子,都让 其出圈,取消候选资格。然后不停地按顺时 针方向逐一让报出m者出圈,最后剩下一个 就是猴王。
2020/6/10
12
演示:n=8, m=3
8 7
起始位置 1
2
3
猴王
6
猴子被淘汰的顺序 3
2020/6/10
5 61
4 52
84
13
说明:
如图1所示有8只猴子围成一圈,m=3。从1# 猴的位置开始,顺时针1至3报数,第一个出 圈的是3#;第二个出圈的是6#,第3个出圈 的是1#;第4个出圈的是5#;第5个是2#,第 6个是8#;第7个是4#。最后剩下一个是7#, 它就是猴王。
}
// 循环体结束
if (root==null)
// 如果根结点为空
printf("这是一棵空树。\n");// 输出空树信息
else
// 根结点不为空
print(root);
// 调用print函数,输出二叉树内容
} 2020/6/10
// 主函数结束
10
循环链表
2020/6/10
11
循环链表
q=p; 2020/6/10
// q赋值为p
21
for(i=2;i<=nn;i=i+1) // 利用循环结构构造链表
{
// 循环体开始
p=(struct mon *)malloc(LEN);// 为p分配内存空间
p->num=i; // 初始化p结点num域为i,表示猴子号
q->next=p;
// 将p结点加到链表尾部
else
} }
2020/6/10
// 如果p结点数据大于等于根结点数据 insert( &((*proot)->R), p); // 插入右子树
// 函数体结束
8
// 被调用函数,形参为TREE结构指针,输出二叉树内容
void print(struct TREE *root)
{
// 函数体开始
if (root == null)
// 主函数开始 // 函数体开始 // TREE型结构指针 // 临时变量,用于用户输入数据 // 初始化二叉树根结点为空 // 初始化待插入结点的指针为空
printf("请输入待插入结点的数据\n"); // 提示信息
printf("如果输入-1表示插入过程结束\n");// 提示信息
2s02c0a/6/n10f("%d",&temp); // 输入待插入结点数据
}
else q=p;
// q指向相邻的下一个结点p
}while(q!=q->next); // 剩余结点数不为1,则继续循环
head = q;
// head指向结点q,q为链表中剩余的一个结
点2020/6/10
23
void main() {
int n,m; head = null;
// 主函数开始 // 函数体开始 // 声明整型变量n,m // 初始化head为空
2020/6/10
19
#include <stdio.h> #include <malloc.h> #define null 0
// 预编译命令 // 内存空间分配 // 定义空指针常量
// 定义常量,表示结构长度 #define LEN sizeof(struct mon)
struct mon {
// p赋值为q相邻的下一个结点
x=x+1;
// x加1
if(x % mm==0) // x是否整除mm,
{
// 表示是否跳过指定间隔
// 输出被删掉的猴子号
printf("被删掉的猴子号为%d号\n",p->num);
q->next=p->next; // 删除此结点
free(p);
// 释放空间
定义一个递归函数
void insert(struct TREE **proot, struct TREE *p)
其中,指针p指向含有待插入数据的结点。
proot为树的根指针的地址。
insert函数棵理解为将p结点插入到*proot所指向
的树中。
2020/6/10
4
注意在上图中proot是被调用函数的形参。从前面对它 的定义看,proot是指针的指针,实际上是指向二叉 树根结点的指针的指针,或者说是指向二叉树根结点 的指针的地址。如下图。因此,在主程序调用insert 函数时,
insert( &root, p ); // 将p结点插入到根为root的树中,
// &root表示二叉树根结点的地址
printf("请输入待插入结点的数据\n"); // 提示信息
printf("如果输入-1表示插入过程结束\n");// 提示信息
scanf("%d",&temp);
// 输入待插入结点数据
int num; struct mon *next; };
// 结构声明
// 整型数,用于记录猴子号 // mon结构指针
struct mon *head, *tail; // mon结构指针,全局变量
2020/6/10
20
void create(int nn) {
int i; struct mon *p,*q;
// 被调用函数 // 函数体开始 // 整型变量i,用于计数 // 声明mon结构指针p,q
// 为p分配内存空间 p=(struct mon *) malloc(LEN);
p->num=1;
// 初始化p结点num域为1
p->next=null;
// 初始化p结点next域为空
head=p;
// 链表头指针head赋值为p
{
// 函数体开始
if (*proot==null)
// 如果根结点为空
{
*proot = p;
// 将结点p插入根结点
return;
// 返回
}
else
// 根结点不为空
{
// 如果p结点数据小于等于根结点数据
if (p->data <= (*proot)->data)
insert( &((*proot)->L), p); // 插入左子树
2020/6/10
15
4、建立循环链表的函数create(int nn) 其中nn为形式参数。要从编号1到编号nn。思路是
(1)先做第1个结点,让其中的数据域p->num赋值为1,让 指针域赋值为null。之后让链头指针head指向第1个结点。 利用指针q记住这个结点,以便让指针p去生成下面的结 点。
2020/6/10
3
对二叉树最重要的是根,它起定位的作用,因此,首先 建立的是根结点。也就是说,如果从键盘输入数据来 建立二叉树,第一个数据就是这棵树的根的数据,之 后再输入的数据,每一个都要与根中的数据作比较, 以便确定该数据所在结点的插入位置。假定我们这里 依然用图1的中序遍历的方式。即如果待插入结点的 数据比根结点的数据小,则将其插至左子树,否则插 入右子树。
所在的结点。
设计两个指针p和q。一开始让q指向链表的尾部q=tail。 让p指向q的下一个结点。开始时让p指向1#猴所在的结点。 用一个累加器x,初始时x=0,从1#猴所在结点开始让 x=x+1=1,如果mm是1的话,1#猴所在的p结点就要被删 除。有三条语句
printf(“被删掉的猴子号为%d号\n”,p->num);
9
while(temp != -1)
// 当型循环,-1为结束标志
{
// 循环体开始
// 为待插入结点分配内存单元
p = (struct TREE *) malloc(LEN);
p->data = temp; // 将temp赋值给p结点的数据域
p->L = p->R = null; // 将p结点的左右指针域置为空
void select(int mm)
{
// 函数体开始
int x=0;
// 声明整型值x,并初始化为0
struct mon *p,*q;
// 声明结构指针p,q
q=tail;
// q赋值为tail,指向循环链表尾部
do
// 直到型循环,用于循环删除指定间隔的结点
{
// 循环体开始
p=q->next;
二叉树的建立 循环链表 文件操作
2020/6/10
1
二叉树的建立
2020/6/10
2
二叉树的建立
建立二叉树的过程是一个“插入”过程,下面我们用 一个例子来讲解这一过程。
我们想建立这样一棵二叉树,树中的每一个结点有一 个整数数据名为data,有两个指针:左指针L,右指 针R,分别指向这个结点的左子树和右子树,显然 可以用如下名为TREE的结构来描述这种结点: struct TREE { int data; struct TREE *L, *R; }
q=p;
// 让q指向链表尾部结点
p->next=null; // 链表尾部指向空
}
// 循环体结束
tail = q;
// 链表尾
tail->next=head; // 链表尾部指向链表头,
// 形成循环链表
} 2020/6/10
// 函数体结束
22
// 被调用函数select,mm表示结点删除间隔
(2)利用一个计数循环结构,做出第2个结点到第nn个结点。 并将相邻结点一个接一个链接到一起。
(3)最后一个结点要和头结点用下一语句链接到一起
tail = q; tail->next = head;
q
head
tail
2020/6/10
16
5、删结点的函数select(int mm) mm为形式参数,从1至m报数,凡报到mm者删除其
实参
根结点
&root
proot
实参为 &root, p
形参为 proot, p
下面是建立二叉树的参考程序。
2020/6/10
6
#include <stdio.h>
// 预编译命令
#include <malloc.h>
// 内存空间分配
#define null 0
// 定义空指针常量
#define LEN sizeof(struct TREE) // 定义常量,表示结构长度
// 根或子树根结点为空
return;
// 返回
print(root->L);
// 输出左子树内容
printf("%d",root->data);// 输出根结点内容
print(root->R);
// 输出右子树内容
}
// 被调用函数结束
void main() {
struct TREE *root, *p; int temp; root = null; p = null;
我们用循环链表来模拟这个选择过程。
2020/6/10
14
1、定义一个名为mon的结构
struct mon
{
int num;
// 整数,表示猴子的编号
struct mon *next; // 指针,指向相邻的下一只猴子
}
2、将链表的头指针head定义为全局变量。 struct mon*head;
3、主函数 用键盘输入猴子数n,输入数m,调用函数create建立一个 循环链表,模拟众猴围成一圈的情况。该函数的实参为n。 调用函数select,模拟1至m报数,让n-1只猴子逐一出列的 过程。即在具有n个结点的循环链表按报数m删除结点的 过程。该函数的实参为m,最后输出猴王的编号。
q->next = p->next;
演示
free(p);
p
head 1
2
q tail 8
2020/6/10
17
这里free(p)是释放p结点所占用的内存空间的语句。 如果mm不是1而是3,程序会在do-while循环中, 让x加两次1,q和p一起移动两次,p指向3#所在结 点,q指向2#所在结点,之后仍然用上述三条语句 删去3#所在的结点。
printf("请输入猴子数\n"); // 提示信息
scanf("%d",&n);
// 输入待插入结点数据
printf("请输入间隔m\n"); // 提示信息
scanf("%d",&m);
// 输入间隔
create(n);
// 调用函数create建立循环链表
select(m);
// 调用函数select,找出剩下的猴子
struct TREE {
int data; struct TREE *L,*R; };
// 结构声明
// 整型数 // TREE结构指针
2020/6/10
7
// 被调用函数insert,将结点插入二叉树
void insert (struct TREE **proot, struct TREE* p)
演示
pq
qp p
q
head 1
2
3
4
8
2020/6/10
18
这个do-while循环的退出条件是q==q->next。即当只 剩下一个结点时才退出循环。当然猴王非其莫属了。 这时,让头指针head指向q,head是全局变量,在 主程序最后输出猴王时要用head->num。
q head 7
Leabharlann Baidu
参考程序如下:
相关文档
最新文档