0
点赞
收藏
分享

微信扫一扫

数据结构课程设计第二周解题报告

老罗话编程 2022-03-15 阅读 73

目录

题目A 手撕STL sort (40 分)

题目B 冬奥会接驳车 (40 分)

题目C 自动纠错 (20 分) 


题目A 手撕STL sort (40 分)

函数接口定义: 

void sort(int *R, int n);
void sort(int *R,int n)
{
	R[n+1]=100000000;//将n+1赋值成无穷大 
	value = 2*log(n)/log(2);//计算递归层数上限 
	printf("depth_limit:%d\n",value);
    QSort(R,1,n,0);//快速排序
	printf("Intermediate:");//无论是否插入排序,都要输出
	for(int i = 1;i<=n;i++)
	{
		printf("%d ", R[i]);
		if(i==n)printf("\n");
	}
    if(flag==1)
    {
    	insertSort(R,n);
	}
	return;
}

解题思路:

本题的目的是实现C++STL库中的sort()排序,它只是简单的排列整数,但是也让我们感受了一波sort的内部实现过程:最开始先快排,在递归层数达到限制2*logn/log2时,在本层对子数组进行堆排序,(防止快排退化)若分划子数组长度可以减小达到threshold值,(插入排序更加合适)做标记,记得最后进行插入排序。值得注意的是:无论是否进行插入排序,"Intermediate:"必然要输出解题思路题目中也已经给出,我们直接看代码吧。 

#include<iostream>
#include<stdlib.h>
#include<math.h>
using namespace std;


int threshold; 
int b[50010];
int value;
int flag = 0;

void restore(int f,int e){ //大根堆 
	int j=f;//指向树根 
	int m;
	while(j<=e/2)
	{
		if(2*j<e&&b[2*j]<b[2*j+1]) m=2*j+1;
		else m=2*j;
		
		if(b[m]>b[j])
		{
			swap(b[m],b[j]);
			j=m;
		}
		else j=e;
	}
}
void heapSort(int *R,int m,int n)//堆排序 
{	
    //初始建堆 
	int len= n- m +1;
	for(int i=len/2;i>=1;i--){
		restore(i,len);
	}
	printf("Heap:");//输出初始建堆的子数组 
    for(int i = 1;i <= len;i++)
    {
    	printf("%d ",b[i]);
    	if(i==len)printf("\n");
	}
	// 堆排序 
	for(int i=len;i>=2;i--)
	{
		swap(b[1],b[i]);
		restore(1,i-1);
	}
	return;
}

int Partition(int *R,int m,int n)
{//分划函数,按照要求,以第一个元素为基准元素 
	int i = m, j = n+1, k = R[m];
	while(i<j)
	{
		i++;
		while(R[i]<=k){i++;}
		j--;
		while(R[j]>k){j--;}
		if(i<j){swap(R[i],R[j]);}
	}
	swap(R[m],R[j]);
	return j;
}

void QSort(int *R,int m,int n,int depth)
{
	if(m<n)
	{	
    	if(n-m+1<=threshold)
	   	{
	      	flag = 1;//若分划可以达到threshold值,记得最后插入排序 
	       	return;
	    }
	    else if(depth==value)
    	{
    		int Length = n-m+1;
    		int p =m;
		   	for(int i =1;i<=Length;i++)
          	{
	        	b[i] = R[p++];
        	}
	    	heapSort(b,1,Length);
	    	p= m;
	    	for(int i =1;i<=Length;i++)
        	{
	        	R[p++] = b[i];
        	}	
	    	return;
	   	}
    	else
	   	{
    	   	int j = Partition(R,m,n);
     	   	QSort(R,m,j-1,depth+1);
	       	QSort(R,j+1,n,depth+1);
	       	return;
	   	}
    }
}

void insertSort(int *R,int n)
{
	int j;
	int value0;
	for(int i = 2;i<=n;i++)
	{
        for (j = i - 1; j >= 0; j--)
            if (R[i] > R[j])break;
            if (j != i - 1)
            {
                value0  = R[i];
                for (int k = i - 1; k > j; k--)
                    R[k + 1] = R[k];
                R[j + 1] = value0;
            }
     }
}


void sort(int *R,int n)
{
	R[n+1]=100000000;//将n+1赋值成无穷大 
	value = 2*log(n)/log(2);//计算递归层数上限 
	printf("depth_limit:%d\n",value);
    QSort(R,1,n,0);
	printf("Intermediate:");
	for(int i = 1;i<=n;i++)
	{
		printf("%d ", R[i]);
		if(i==n)printf("\n");
	}
    if(flag==1)
    {
    	insertSort(R,n);
	}
	return;
}


int main()
{
    int n,i;
    int a[50010];
    scanf("%d %d", &n, &threshold);
    for (i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    
    sort(a,n);
    
    printf("Final:");
    for (i = 1; i <= n; i++)
        printf("%d ",a[i]);
    printf("\n");
    return 0;
}

 题目B 冬奥会接驳车 (40 分)

解题思路+注意:

这道题就是典型的迷宫问题 ,站在某一块空地上,只能朝前后左右四个方向走去,第一个思路应该是回溯法+深度优先搜索,但是深度优先搜索对于找最短路径迷宫问题,深搜就有些效率不高,因为找到一条通路我们也没法保证他就是最短的路径。如果用广度优先遍历的话,就可以一层一层找,将队列头部节点所有符合情况的儿子节点放入队列,如果出现到达目的地的情况,显然就是最短情况。

题目中用到的数据结构是队列,由于不允许使用STL,所以我简单模拟了Queue,first是头指针,rear是尾指针。

需要注意到的是,要防止数组访问越界,因为不是对任意一块空地,都可以朝四个方向走,并且为了优化,我做了一个标记,记录到达此块空地的方式,例如:若到某块空地是由上一步向下移动得来的,那么从这块空地出发时,就不再向上了;若到某块空地是由上一步向左移动得来的,那么从这块空地出发时,就不再向右了。虽然进入过队列的节点之后也一定不会再进入队列,因为box[i][j]值被赋值-1,变成了不可走的格子,但是通过做标记跳过一种情况可以相对减少一些赋值和比较操作,更节省时间。

 代码如下:

#include<bits/stdc++.h>
using namespace std;


int box[102][102];

struct site
{
	int i;
	int j;
	int ceng ;//层数
	int num0;//标记自己是怎么得来的。 
};
typedef struct 
{
	site data[10005];
	int first ;
	int rear;
}Queue;

Queue store;
int path(int n, int m,int x1,int y1,int x2,int y2)
{
	int i,j;
	int Case;
	store.first = 0;
	store.rear = 0;
	store.data[store.rear].i = x1;
	store.data[store.rear].j = y1;
	store.data[store.rear].ceng = 0;
	store.data[store.rear].num0 = -1;
	store.rear++;
	box[x1][y1] = -1 ;//入队列标记负值
	while(store.first != store.rear)
	{
		Case = -1;
		while(Case<4)
		{
			Case++;
			if(Case==(store.data[store.first].num0+2)%4)continue;//若它由向下移得来,则不考虑向下移动
			switch(Case)
			{
				case 0: {i = store.data[store.first].i;j = store.data[store.first].j-1;break;}//向上 
				case 1: {i = store.data[store.first].i+1;j = store.data[store.first].j;break;}//向右 
				case 2: {i = store.data[store.first].i;j = store.data[store.first].j+1;break;}//向下 
				case 3: {i = store.data[store.first].i-1;j = store.data[store.first].j;break;}//向左 
			}
			
			if((box[i][j]==0)&&i>=0&&j>=0)
			{
			    store.data[store.rear].i = i;
			    store.data[store.rear].j = j;
			    store.data[store.rear].num0 = Case;//记住它是怎么得来的
			    store.data[store.rear].ceng = store.data[store.first].ceng+1;
                box[i][j] = -1 ;//入队列标记负值
			    store.rear = (store.rear+1)%10000;
			}//找到可以走的格子
			else if(i == x2 && j == y2)
			{
				return store.data[store.first].ceng + 1;
			}
		}
        //box[store.data[store.first].i][store.data[store.first].j] = 0;
		store.first = (store.first+1)%10000;
	}
	return 0;
}

int main()
{
	int n,m;
	int x1,y1,x2,y2;
	while((scanf("%d %d",&n,&m))!=EOF)
	{
		memset(box,1,sizeof(box));
		for(int i = 0;i < n;i++)
    	{
    		for(int j = 0;j < m;j++)
	    	{
	    		scanf("%d",&box[i][j]);
	    		if(box[i][j]==3){x1=i,y1=j;}
	   	    	if(box[i][j]==4){x2=i;y2=j;}
       		}
    	}
    	int sum = path(n,m,x1,y1,x2,y2);
    	if(sum==0)
    	{
    		printf("unreachable\n");
		}
		else
		{
			printf("%d\n",sum);
		}
	}
	return 0;
}

题目C 自动纠错 (20 分) 

解题思路:

这道题的整体思路已经给出,

建字典树(buildTree(int n)):

每存一个单词,都从树的节点开始遍历,然后计算经过节点与所存单词的编辑距离冷,接着访问第len个儿子,直到遍历到空指针。把此单词存入。

检索(queryWord(char str[],node *root,int d))

递归检测,当len==0,证明找到单词,然后做标记结束递归。当len<=d,符合条件,然后选取最大频率的。

求解编辑距离(stringMatch_MaxSize(char *str1,char *str2))

关键的算法:计算两个字符串的距离(即两个字符串的编辑距离)。

详细见题目中的详细思路,具体实现看代码。

代码如下:

#include<bits/stdc++.h>
using namespace std;

struct node
{
	char str[20];
	int num;
	node *next[20]={NULL};
};

node * treeRoot = new node; //字典树的根节点
int maxNum = 0;//最大频率
char similarWord[20];//保留需要输出的单词
int flag = 0;//标记是否距离有<=d的单词或者单词本身


struct dot
{
	char str[20];
	int num;
};

dot word[10010];

int stringMatch_MaxSize(char *str1,char *str2)
{   
    //计算编辑距离
	int max_len[20][20];
	memset(max_len,0,sizeof(max_len));
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	
	//初始化 
	for(int i = 1; i<=len1; i++)
	{
		max_len[i][0]= i;
	}
	for(int i = 1; i<=len2; i++)
	{
		max_len[0][i] = i;
	}
	
	for(int i = 1;i<=len1;i++)
	{
		for(int j = 1; j<=len2; j++)
		{
			if(str1[i-1]==str2[j-1])
			{
				max_len[i][j] = max_len[i-1][j-1];
			}
			else
			{
				if(max_len[i][j - 1] < max_len[i-1][j])max_len[i][j] = max_len[i][j- 1];
				else max_len[i][j] = max_len[i-1][j];
				if (max_len[i][j] > max_len[i - 1][j - 1]) max_len[i][j] = max_len[i - 1][j - 1];
				max_len[i][j] += 1;
			}
		} 
	}
	return max_len[len1][len2];	
}

void buildTree(int n)
{
	node * p;
	for(int i=1;i<n;i++)
	{
		//printf("treeRoot:%s\n",treeRoot->str);
		//printf("word[%d]:%s\n",i,word[i].str);
	    p = treeRoot; 
		int len = stringMatch_MaxSize(p->str,word[i].str);
		while(p->next[len]!=NULL&&len>0)
		{
			//printf("len:%d\n",len);
			p = p->next[len];
			len = stringMatch_MaxSize(p->str,word[i].str);
		}
		if(len == 0)continue;
		if(p->next[len]==NULL)
		{
			p->next[len] = new node;
			strcpy(p->next[len]->str,word[i].str);
			p->next[len]->num = word[i].num;
		}
	}		
}

void queryWord(char str[],node *root,int d)
{
	if(root==NULL)return;
	int len = stringMatch_MaxSize(root->str,str);
	if(len == 0)
	{
		//printf("找到了!!!!\n");
		flag=1;
        memset(similarWord,'\0',sizeof(similarWord));
	    strcpy(similarWord,root->str);
    	return;
	}
	else if(len<=d)
	{
		//printf("长度小,欸嘿!!!:%d\n",len); 
		flag=2;
		if(maxNum<root->num)
		{
			maxNum=root->num;
            memset(similarWord,'\0',sizeof(similarWord));
		    strcpy(similarWord,root->str);
		}
		else if(maxNum==root->num)
		{
			if(strcmp(similarWord,root->str)>0)
			{
                memset(similarWord,'\0',sizeof(similarWord));
				strcpy(similarWord,root->str);
			}
		}
	}
	int m1;
	if(len-d<=0){m1=1;}
    else {m1 = len-d;}
    int m2;
    if(len +d >15){ m2 = 15;}
    else{m2 = len +d;}
	for(int i = m1; i<= m2 ; i++)
	{
		if(flag==1)break;
		//printf("开始搜索字子树!!!\n");
		queryWord(str,root->next[i],d);
	}
	//printf("递归呀!!\n"); 
	return;
}

int main()
{
	int n,m,d;
	scanf("%d%d%d",&n,&m,&d);
	for(int i = 0;i < n; i++)
	{
		scanf("%d%s",&word[i].num,word[i].str); 
	}          
	strcpy(treeRoot->str,word[0].str);//初始化根节点 
	treeRoot->num = word[0].num;
	buildTree(n);
	for(int i = 0; i < m; i++)
	{
		char findWord[20];
		memset(findWord,'\0',sizeof(findWord));
		memset(similarWord,'\0',sizeof(similarWord));
		flag = 0;
		maxNum = 0;
		scanf("%s",findWord);
		queryWord(findWord,treeRoot,d);
		if(flag>=1)printf("%s\n",similarWord);
		else{printf("No similar word in dictionary\n");}
	}
	return 0;
}

请勿抄袭哈! 

 

 

举报

相关推荐

0 条评论