22 软专

数据结构

第一题

1、高度平衡二叉树即任意节点的左右子树的高度之差绝对值不差过1的二叉树,已知一颗二叉树采用二叉链表存储,编写算法判断是否是高度平衡二叉树
解法1:

高度平衡二叉树的判定主要有两种判定方法,一个是自上而下,从根节点到叶节点逐步判定,写法为:

  1. 递归出口:节点为空返回1
  2. 求左右子树高度
  3. 判断当前节点的左右子树高度差是否大于1,同时递归判断左右子树
  4. 缺点:做了很多不必要的比较

代码:

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次即可,每个元素只需比较一次,时间复杂度相比于前面一个复杂度要小

  1. 类似于后序遍历,求高度的改写
  2. 递归出口:根节点为空,返回0
  3. 分别递归左右子树的高度
  4. 如果存在一颗子树的左右子树高度差大于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位不同的话,则说明需要重新求失败函数

  1. 思路大致是,不断地迭代,从前面的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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值