一、思维导图
二、今日练习
2.1 折半查找
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int half(int key,int *p,int low,int high)
{
while(high<=low)
{
int mid=(low+high)/2;
if(key==*(p+mid))
{
return mid;
}
else if(key>*(p+mid))
low=mid-1;
else
high=mid+1;
}
return -1;
}
int main(int argc, const char *argv[])
{
//折半查找
int arr[]={99,88,77,66,55,44,33,22,11};
int low=sizeof(arr)/sizeof(arr[0])-1,high=0;
int *p=arr;
int key;
printf("please enter key:");
scanf("%d",&key);
int sub=half(key,p,low,high);
if(sub==-1)
printf("key不存在!\n");
else
printf("find key in %d\n",sub);
return 0;
}
2.2 哈希表查找
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
//哈希表是借助于单链表实现的
typedef int datatype;
typedef struct Node
{
//数据域
datatype data;
//指针域
struct Node *next;
}*node;
/*
* function: 计算最大质数
* @param [ in]
* @param [out]
* @return
*/
int max_prime(int m)
{
for(int i=m;i>=2;i--)
{
int count=0;
//i:m~2
//判断i是否是质数,如果是则返回,不是则继续
for(int j=2;j<=sqrt(i);j++)
{
if(i%j==0)
{
count++;//计算2~sqrt(i)之间约数的个数
break;
}
if(count==0)
return i;
}
}
}
/*
* function: 节点创建
* @param [ in]
* @param [out]
* @return
*/
node create_node()
{
node s=(node)malloc(sizeof(struct Node));
if(NULL==s)
return NULL;
s->data=0;
s->next=NULL;
return s;
}
/*
* function: 哈希表的插入
* @param [ in]
* @param [out]
* @return
*/
node insert_hash(int key,int p,node hash[])
{
int sub=key%p;
node L=hash[sub];
//创建新节点s
node s=create_node();
s->data=key;
if(L!=NULL)
{
s->next=L;
}
L=s;
return L;
}
/*
* function: 哈希表输出
* @param [ in]
* @param [out]
* @return
*/
void output(node hash[],int p)
{
for(int i=0;i<p;i++)
{
printf("%d: ",i);
node L=hash[i];
if(L==NULL)
{
puts("NULL!");
continue;
}
while(L!=NULL)
{
printf("%d\t",L->data);
L=L->next;
}
puts("NULL");
}
}
/*
* function: 哈希表查找
* @param [ in]
* @param [out]
* @return
*/
int search_hash(datatype key,int p,node hash[])
{
int sub=key%p;
printf("sub=%d\n",sub);
if(hash[sub]==NULL)
{
return -1;
}
node L=hash[sub];
while(L!=NULL)
{
if(L->data==key)
{
return 0;
}
L=L->next;
}
return -1;
}
/*
* function: 哈希表释放
* @param [ in]
* @param [out]
* @return
*/
node free_space(node hash[],int p)
{
for(int i=0;i<p;i++)
{
while(hash[i]!=NULL)
{
node q=hash[i];
hash[i]=hash[i]->next;
free(q);
q=NULL;
}
}
}
int main(int argc, const char *argv[])
{
//把数组的元素存到哈希表中,再通过哈希表实现查找
int arr[]={67,54,41,67,1093,2345,2345,123,34,123};
int len=sizeof(arr)/sizeof(arr[0]);
int m=len*4/3;
int p=max_prime(m);
//构建哈希表
node hash[p]; //指针数组,存储p个指针
for(int i=0;i<p;i++)
{
hash[i]=NULL;
}
//把数组元素存到哈希表
//
for(int i=0;i<p;i++)
{
hash[arr[i]%p]=insert_hash(arr[i],p,hash);
}
//输出哈希表
output(hash,p);
//查找
datatype key;
printf("pleast enter key:");
scanf("%d",&key);
int flag=search_hash(key,p,hash);
if(flag==0)
puts("success");
else
puts("error");
//释放
free_space(hash,p);
output(hash,p);
return 0;
}
2.3 利用递归输出5 4 3 2 1
效果等同于n=5 ; n<=0 ; n--
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void rec(int n)
{
if(n==0)
return;
else
{
printf("%d\n",n);
}
rec(n-1);
}
int main(int argc, const char *argv[])
{
//实现n的阶乘
int n=5;
rec(n);
return 0;
}
调用过程:
递归循环5次:
2.4 用递归实现n的阶乘【n!】
n!=n*n-1*n-2*n-3*...*1
5!=5*4*3*2*1=120
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int rec(int n)
{
static int p=1;
if(n==0)//n!:0!=1
return 1;
else
{
/*
p*=n;
rec(n-1);
return p;
*/
return n*=rec(n-1);
}
}
int main(int argc, const char *argv[])
{
//利用递归实现n的阶乘(5!=5*4*3*2*1)
int n;
printf("please enter n=");
scanf("%d",&n);
int p=rec(n);
printf("%d!= %d\n",n,p);
return 0;
}
2.5 用递归实现斐波那契数列
斐波那契数列 1 1 2 3 5 8 13.....
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int Fibonaci(int n)
{
if(n==1 || n==2)
{
return 1;
}
else
{
return Fibonaci(n-1)+Fibonaci(n-2);
}
}
int main(int argc, const char *argv[])
{
//利用递归实现斐波那契数列
int n;
printf("please enter n=");
scanf("%d",&n);
int num=Fibonaci(n);
printf("第%d项斐波那契数是:%d\n",n,num);
for(int i=1;i<=n;i++)
{
printf("%d\t",Fibonaci(i));
}
puts("");
return 0;
}
调用过程:
2.6 用递归实现建立树、先中后序遍历、输出、释放
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef char datatype;
typedef struct Node
{
//数据域
datatype data;
//左孩子
struct Node *lchild;
//右孩子
struct Node *rchild;
}*Btree;
/*
* function: 创建二叉树
* @param [ in]
* @param [out]
* @return 返回根节点的地址
*/
Btree create_tree()
{
datatype e;
printf("Please enter tree data:");
scanf(" %c",&e);
if(e=='#')
return NULL;
Btree tree=(Btree)malloc(sizeof(struct Node));
if(tree==NULL)
return NULL;
tree->data=e;//赋数据域
//创建左子树
puts("左孩子");
tree->lchild=create_tree();
//创建右子树
puts("右孩子");
tree->rchild=create_tree();
return tree;
}
/*
* function: 先序遍历
* @param [ in]
* @param [out]
* @return
*/
void first_output(Btree tree)
{
if(tree==NULL)
{
return;
}
printf("%c\t",tree->data);
first_output(tree->lchild);
first_output(tree->rchild);
}
/*
* function: 中序遍历
* @param [ in]
* @param [out]
* @return
*/
void mid_output(Btree tree)
{
if(tree==NULL)
{
return;
}
mid_output(tree->lchild);
printf("%c\t",tree->data);
mid_output(tree->rchild);
}
/*
* function: 后序遍历
* @param [ in]
* @param [out]
* @return
*/
void last_output(Btree tree)
{
if(tree==NULL)
{
return;
}
last_output(tree->lchild);
last_output(tree->rchild);
printf("%c\t",tree->data);
}
/*
* function: 计算n0,n1,n2
* @param [ in]
* @param [out]
* @return
*/
void Count(Btree tree,int *n0,int *n1,int *n2)
{
if(tree==NULL)
return;
else if(tree->lchild==NULL &&tree->rchild==NULL)
++(*n0);
else if(tree->lchild!=NULL &&tree->rchild!=NULL)
++(*n2);
else
++(*n1);
Count(tree->lchild,n0,n1,n2);
Count(tree->rchild,n0,n1,n2);
}
/*
* function: 树的度
* @param [ in]
* @param [out]
* @return
*/
int High(Btree tree)
{
if(tree==NULL)
return 0;
int left=High(tree->lchild)+1;
int right=High(tree->rchild)+1;
return left>right?left:right;
}
/*
* function: 树的释放【采用后续遍历释放】
* @param [ in]
* @param [out]
* @return
*/
Btree free_space(Btree tree)
{
if(tree==NULL)
return NULL;
free_space(tree->lchild);
free_space(tree->rchild);
free(tree);
tree=NULL;
}
int main(int argc, const char *argv[])
{
//tree
//创建并输入,递归
Btree tree=create_tree();
//先序遍历:根左右
puts("先序遍历:");
first_output(tree);
//中序遍历:左根右
puts("\n中序遍历:");
mid_output(tree);
//后序遍历:左右根
puts("\n后序遍历:");
last_output(tree);
int n0=0,n1=0,n2=0;
Count(tree,&n0,&n1,&n2);
printf("n0=%d\tn1=%d\tn2=%d\n",n0,n1,n2);
int h=High(tree);
printf("高度是:%d\n",h);
tree=free_space(tree);
first_output(tree);
puts("释放成功");
return 0;
}
三、作业
3.1 【多选题】在一棵度为3的树中,度为3的结点数为2个,度为2的结点数为1个,度为1的结点数为2个,则度为0的结点数不可能为 ( )个。
A. 6
B. 7
C. 4
D. 5
解析:
选BCD
先算出这棵树中一共有几个节点:n=n0+n1+n2+n3
现在未知n=几?
由于在任意一颗二叉树中,叶子节点(n0)的数目比 度为2(n2)的节点的数目多1
∴ n=n×n3+n×n2+n×n1+1
=3*2+2*1+1*2+1
=11
n=n0+n1+n2+n3
11=n0+2+1+2
11=n0+5
∴ n0=6
排除BCD即可
建议画图
3.2【多选题】设树T的度为4,其中度为1,2,3和4的结点个数分别为4,2,2,1 则T中的叶子数不可能是 ( )个。
A. 5
B. 8
C. 6
D. 10
解析:
选ABC
先算出这棵树中一共有几个节点:n=n0+n1+n2+n3
现在未知n=几?
由于在任意一颗二叉树中,叶子节点(n0)的数目比 度为2(n2)的节点的数目多1
∴ n=n×n3+n×n2+n×n1+1
=1*4+2*2+3*2+4*1+1
=19
n=n0+n1+n2+n3
n0=19-4-2-2-1=10
∴ n0=10
建议画图
3.3 深度为5的完全二叉树最少有多少个结点 (C)
A. 32
B. 16
C. 31
D. 15
解析:
解析:
第一层:1个
第二层:2个
第三层:4个
第四层:8个
第五层:16个
总:31
3.4 已知一棵完全二又树有500个结点,则这棵树的深度是 (D)
A. 7
B. 8
C. 10
D. 9
3.5 若对一棵有16个结点的完全二叉树按层编号,则对于编号为7的结点x,它的双亲结点及右孩子结点的编号分别为(B)
A. 2,15
B. 3,15
C. 2,14
D. 3,14
3.6 【多选题】一个具有63个结点的二叉树的高h的值可能是 (ABD) 。
A. 63
B. 10
C. 5
D. 6
解析:
在深度为k的二叉树上,最多有2^k-1个节点(k>=1)
2^5-1=31
∴不是答案
3.7 已知一棵完全二叉树有5层,则第5层最少和最多分别有 (A)个结点
A. 1,16
B. 2,15
C. 1,31
D. 1,17
3.8 已知遍历结果如下,试画出对应的二叉树
前序: ABCEHFIJDGK
中序: AHECIFJBDKG
3.9 已知树的先序遍历是GDAFEMHZ,中序遍历是ADEFGHMZ,则后序遍历的结果是 ( C )
A. AEFDMZHG
B. ADFEHZMG
C. AEFDHZMG
D. AMZHEFDG
3.10 已知某二又树的后序遍历序列是dabec,中序遍历序列是debac,它的先序遍历序列是 ( B )
A. acbed
B. cedba
C. decab
D. deabc