数据结构
第一题
1、高度平衡二叉树即任意节点的左右子树的高度之差绝对值不差过1的二叉树,已知一颗二叉树采用二叉链表存储,编写算法判断是否是高度平衡二叉树
解法1:
高度平衡二叉树的判定主要有两种判定方法,一个是自上而下,从根节点到叶节点逐步判定,写法为:
- 递归出口:节点为空返回1
- 求左右子树高度
- 判断当前节点的左右子树高度差是否大于1,同时递归判断左右子树
- 缺点:做了很多不必要的比较
代码:
typedef struct tnode{
int data;
struct tnode *left, *right;
}*tree;
int BtDepth(tree root){
if(root == NULL) return 0;
int l = BtDepth(root->left);
int r =BtDepth(root->right);
return (l>r?l:r)+1; //左右子树高度较大的加1
}
bool Judge_AVL(tree T){
if(T == NULL){
return 1;
}
else{
int hl = BtDepth(T->left);
int hr = BtDepth(T->right);
if(abs(hl-hr) < 1){
return Judge_AVL(T->left) && Judge_AVL(T->right);
}
else{
return 0;
}
}
}
解法2
采用自底向上的算法判断,从根节点开始进行判断,如果左右子树中存在高度差大于1的节点,那么整颗二叉树都不是高度平衡二叉树,这里只需要比较n次即可,每个元素只需比较一次,时间复杂度相比于前面一个复杂度要小
- 类似于后序遍历,求高度的改写
- 递归出口:根节点为空,返回0
- 分别递归左右子树的高度
- 如果存在一颗子树的左右子树高度差大于1,返回-1,如果左子树高度差大于1,或者右子树高度大于1,返回-1,这里-1表示的是左右子树高度差大于1
代码:
typedef struct tnode{
int data;
struct tnode *left, *right;
}*tree;
//自下而上的算法实现,类似于后序遍历
int deep(tree root){
if(root==NULL){
return 0;
}
int l = deep(root->left);
int r = deep(root->right);
if(abs(l-r)>1 || l == -1 || r == -1){ //如果左右子树有一个不平衡或者根节点不平衡,那么整颗树也不平衡
return -1;
}
return (l>r?l:r)+1; //返回左右子树中较大的高度
}
bool isbalace(tree root){
return deep(root)>=0;
}
第二题
2、对半插入的排序的思想是:在插入Ri时,(这是R1,R2,Ri-1已经排好序)取k[i/2]与ki进行比较 ,如果ki<k[i/2],则Ri只能插入在R1与R[i/2] ,所以可以在Ri与 R[i/2]-1之间递归上述过程否则可以在R[i/2]+1与Ri-1 之间递归上述过程,如此进行直到最后确定插入位置位置,请给出对半插入的排序算法并分析算法的时间复杂度
思路:
按照题意模仿即可,主要是有点忘了,记录一下
void InsertSort(int R[], int n){
int i,j,low,high,mid;
for(i=1;i<n;i++){ //插入n-1个元素
int temp = R[i];
low = 0;
high = i-1;
while(low <= high){ //折半查找
mid = (high+low)/2;
if(R[mid] > temp){
high = mid-1;
}
else{
low = mid+1;
}
}
for(j=i;j>=high+1;j--){ //后移操作
R[j] = R[j-1];
}
R[high+1] = temp; //插入
}
}//O(nlog2n)
程序设计
第一题 字符串匹配
3、编写函数int find(char *s1, char *s2)统计字符串s2,在s1中出现的次数,其中字符串以’\0’为结束符
思路:
吉林大学的失败函数与王道408求nextval数组基本一致,如果比较到了第j位,如果失败函数中k+1位于第j位不同的话,则说明需要重新求失败函数
- 思路大致是,不断地迭代,从前面的j-1位已知失败函数中找到第j位和第k+1位相同的元素,找到了就赋值为k+1,一直没找到就赋值为-1
while(p[i]!=p[k+1] && k>=0){
k = f[k]; //找到j项与k+1项相同的k,同时不能越界
}
整体的失败函数fail:
void fail(char *p, int f[]){
int i,k;
int n = strlen(p);
f[0] = -1; //初始化失败函数的第一个位置
for(i=1;i<n;i++){ //迭代求后面函数的失败函数
k = f[i-1]; //k指向当前位置的前一个元素,前k项与第j-1往前找k项相同,如果第k+1项与第j项不同
while(p[i]!=p[k+1] && k>=0){
k = f[k]; //找到j项与k+1项相同的k,同时不能越界
}
if(p[i] == p[k+1]){ //如果相同
f[i] = k+1; //子串长度+1
}
else{
f[i] = -1; //不同,就为-1
}
}
for(int m=0;m<n;m++){
printf("%d ",f[m]);
}
}
回归题目:直接利用失败函数进行比较,如果模式串已经全部匹配,计数器加1,同时指针重新置为从0,继续匹配,直到主串匹配完
//匹配函数
int find(char *s1, char *s2){ // 统计s2在s1中出现的次数
int i=0,j=0,count=0;
int len1 = strlen(s1);
int len2 = strlen(s2);
int f[len2];
fail(s2,f); //得到失败函数
if(len2 > len1) return 0; //如果s2长度大于s1,直接返回0
while(i<len1 && j < len2){
while(s1[i] == s2[j]){ //匹配成功,继续匹配
i++;
j++;
}
if(j==len2){ //已经成功出现一次,次数加1,然后继续匹配
count++;
j=0;
}
else if(j==0){ //第一次匹配就失败,主串下一个字符开始匹配
i++;
}
else{
j = f[j-1]+1; //模式串下一个应该匹配的位置
}
}
return count;
}
第二题 文件操作----读文件
注意事项: 在读文件过程中,最好不要在while中加feof函数,因为在执行过程中,有可能已经从文件中读取了不适合的数据,然后还在插入,最后会导致最后一项乱码,所以,每次读取的过程中,去判断是否读错了,如果读错了,直接break就好了。
//5、每条购物记录包含产品名称,单价、数量、花费总额等信息,编写create函数实现从文件中读入所有购物记录,构建一个单链表,假设文件中的存储信息与结构体信息格式对应,要求文件名有函数的形式参量传入
typedef struct shops{
char name[20];
int num;
int price;
int expense;
struct shops *next;
}shops;
shops* create(char *s){
int end;
FILE *fp = fopen(s,"r");
shops *head = (shops*)malloc(sizeof(shops));
shops *p,*r=head;
fscanf(fp,"%s%d%d%d",head->name, &head->num, &head->price, &head->expense);
head->next = NULL;
while(1){ //文件光标后面还有字符返回0,没有字符返回1
p = (shops*)malloc(sizeof(shops));
end = fscanf(fp,"%s%d%d%d",p->name,&p->num,&p->price,&p->expense);
if(end==EOF) break; //读取到结束了,则直接break,不要再插了,插了就报错
p->next = r->next;
r->next = p; //尾插法
r = p;
}
fclose(fp);
return head;
}
//6、假定input1.txt,intput2.txt中分别存放32个人的所有购物记录,编写函数,完成如下工作:利用create函数创建单链表,计算每个人的购物总开销,返回两个人购物总开销的差额
int Count_Dif(){
char s1[20] = "input1.txt";
char s2[20] = "input2.txt";
int sum1=0,sum2=0;
shops *shops1 = create(s1);
shops *shops2 = create(s2);
shops *p1=shops1,*p2=shops2;
while(p1!=NULL){
sum1+=p1->expense;
p1 = p1->next;
}
while(p2!=NULL){
sum2+=p2->expense;
p2 = p2->next;
}
return abs(sum1-sum2);
}