计算机应用编程实验

本博文涉及的代码都已上传到github上,如果想看可以自行下载。
github代码

1.使用Hash技术检索字符串

本次实验有三个子实验,实验简单,只说一下在编程中遇到的问题,希望可以帮到一些人

  • 使用两个数组来进行字符串的匹配
  1. 读取文本文件时出现乱码,原因是文件的编码格式不对,应该是ANSI编码格式,百度了一下,发现该编码格式是最基本的中文编码格式,GBK也只是它的一种变体形式。
  2. 读取文件时读取一行字符时,输出到结果文件会换行,也就是读取时把换行符也作为该字符串的有效字符读取到,解决方法是读取字符串时一个一个字符的读取,并对换行符进行判断。
  3. 比较计数器为int类型是发生溢出现象,使用long long类型就避免了溢出的可能性。
  • 使用Hash链表进行字符串的匹配操作
  1. Hash函数的返回值是unsigned int类型,那么hash的地址空间也应该和unsigned int相匹配不然就会出现数组下标越界访问的错误,在该程序中并不需要如此大的Hash空间,故可在Hash函数的出口模一个实际长度
  2. 在匹配时,原则上匹配成功一次,那么可以在插入hash表时可以不插入重复的元素,减少相同元素重复开辟空间
  3. 读到最后一个字符串时,最后一个字符的下一个字符就是文件的结束标志,所以最后一个字符串需要在循环外单独进行插入和匹配判断
  • 使用Bloom Filter进行字符串匹配
  1. 使用字符数组作为位数组,在建立Hash值与字符数组中的位关系映射时采用除8模8的方式,导致了几乎全部匹配成功,经发现该映射错误,应该是模8
  2. Hash函数中可能会出现数组的访问越界错误,关键在于对length的处理上,该程序使用固定的length值,在头文件中进行宏定义len

2.使用树结构检索字符串

本次实验有四个子实验

  • 使用平衡二叉树完成字符串检索
    代码借鉴于平衡二叉树
    博文叙述简明,代码详细周全,不再赘述。只是说一下,在本次实验中的一个小问题:
    在查找时,没有较好理解两个字符串比较操作,把两个字符当作是有符号数的比较,导致程序统计27万多的匹配成功串,正好有一半的概率出错,实际上,OS读入文件时把字符串都变成了01串,只不过在程序中显示的是字符,在直观上理解也应该是把01串看成是无符号数,然后把比较函数做成是无符号数比较时,程序就能正确输出所有的可以匹配成功的串。
  • 使用B+树完成字符串检索
    代码借鉴于B+tree详解及实现(C语言)
    该博文讲解到位,代码注释清晰易读,但是在本次实验中我们需要在树节点中存储字符串,所以还需要对代码进行修改,如果在大一学C语言“指针和二维数组”一节时写过多个字符串的冒泡排序法,程序就可能会好改些。该博文代码实现了一棵B*树(比B+树节省空间),如果从树根节点开始向叶子遍历查找一个关键字,是能正确执行的,但是如果从最左的叶子结点开始向右顺序查找时,程序会在某一个中间节点停掉,经过调试,终于找到了错误的原因。
    考虑不周的代码
    示意图
    在这里插入图片描述
    如果按照上面的代码执行,X->next会被置空,提前退出程序。
    下面是调试的代码,如果想验证该程序是否正确,其实就是看tt.txt文件的叶子结点数和ff.txt文件的行数是否相等,把tt.txt文件复制到一个word文档里替换[Level:i],i是层数,数替换的总个数,看和行数是否相等,如果相等,正确,否则错误。
​#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <time.h>

#define M (5) 

typedef struct BPlusNode *BPlusTree;
typedef int KeyType;
struct BPlusNode
{    
	int KeyNum;    
	KeyType Key[M + 1];    
	BPlusTree Children[M + 1];    
	BPlusTree Next;
};


static KeyType Unavailable = INT_MIN;

//生成节点并初始化
static BPlusTree MallocNewNode()
{   
	
	BPlusTree NewNode;    
	int i;    
	NewNode = (BPlusTree)malloc(sizeof(struct BPlusNode));    
	if (NewNode == NULL)        
		exit(EXIT_FAILURE);            
	i = 0;    
	while (i < M + 1)
	{        
		NewNode->Key[i] = Unavailable;        
		NewNode->Children[i] = NULL;        
		i++;    
	}    
	NewNode->Next = NULL;    
	NewNode->KeyNum = 0;
	//输出NewNode结点在堆上的地址 
	printf("%x\n",NewNode);        
	return NewNode;
} 

//初始化
BPlusTree Initialize()
{        
	BPlusTree T;        
	if (M < (3))
	{        
		printf("M最小等于3!");        
		exit(EXIT_FAILURE);            
	}   
	/* 根结点 */    
	T = MallocNewNode();        
	return T;
}

/* 当要对X插入Key的时候,i是X在Parent的位置,j是Key要插入的位置   
当要对Parent插入X节点的时候,i是要插入的位置,Key和j的值没有用 
isKey用来对以上两种状态的区分 
*/
static BPlusTree InsertElement(int isKey, BPlusTree Parent,BPlusTree X,KeyType Key,int i,int j)
{        
	int k;    
	if (isKey)
	{        
		//插入key         
		k = X->KeyNum - 1;   //为即将插入的Key腾地方        
		while (k >= j)
		{            
			X->Key[k + 1] = X->Key[k];
			k--;        
		}
		X->Key[j] = Key;    		//插入j位置
		
		//printf("插入X->Key[j]\n");
		
		//插入子节点一个新的key必须要更新父结点中相应的key                
		if (Parent != NULL)              
			Parent->Key[i] = X->Key[0];                
			
		X->KeyNum++;            
	}
	else
	{        
		//插入节点                
		//对树叶节点进行连接        
		if (X->Children[0] == NULL)
		{   
			BPlusTree tmp;
			if(i > 0)
				tmp = Parent->Children[i-1]->Next;
			         
			if (i > 0)                
				Parent->Children[i - 1]->Next = X;
			           
			X->Next = Parent->Children[i];
			
			if(i == Parent->KeyNum && i > 0)	//要插入的结点对应Parent节点的最后 
				X->Next = tmp; 
			       
		}                
		k = Parent->KeyNum - 1;        
		while (k >= i)
		{            
			Parent->Children[k + 1] = Parent->Children[k];            
			Parent->Key[k + 1] = Parent->Key[k];            
			k--;        
		}        
		Parent->Key[i] = X->Key[0];        
		Parent->Children[i] = X;                
		Parent->KeyNum++;            
	}    
	return X;
}


static BPlusTree SplitNode(BPlusTree Parent,BPlusTree X,int i)
{    
	int j,k,Limit;    
	BPlusTree NewNode;        
	NewNode = MallocNewNode();        
	k = 0;    
	j = X->KeyNum / 2;    
	Limit = X->KeyNum;    
	while (j < Limit)                  //把关键字较大的部分移入NewNode节点中 至多多一个元素 
	{        
		if (X->Children[0] != NULL)     //X不是树叶节点 
		{            
			NewNode->Children[k] = X->Children[j];            
			X->Children[j] = NULL;        
		}  
		
		//元素移入操作      
		NewNode->Key[k] = X->Key[j];        
		X->Key[j] = Unavailable;        
		NewNode->KeyNum++;
		X->KeyNum--;        
		j++;
		k++;    
	}
	if (Parent != NULL)
	{
		InsertElement(0, Parent, NewNode, Unavailable, i + 1, Unavailable);
		//输出以X为表头的链 
		BPlusTree Tmp = X;
		int i=0;
		while (Tmp != NULL){
			i=0;
        	printf(",,,,,,%x\n",Tmp);
        	while(i<Tmp->KeyNum)
        	{
        		printf("%d ",Tmp->Key[i]);
        		i++; 
			}
			printf("\n");
        	Tmp = Tmp->Next;
    	}
    	
	}        
		    
	else
	{        
		//如果是X是根,那么创建新的根并返回        
		Parent = MallocNewNode();        
		InsertElement(0, Parent, X, Unavailable, 0, Unavailable);
		InsertElement(0, Parent, NewNode, Unavailable, 1, Unavailable);
		//输出以X为表头的链
		BPlusTree Tmp = X;
		int i=0;
		while (Tmp != NULL){
			i=0;
        	printf(",,,,,,%x\n",Tmp);
        	while(i<Tmp->KeyNum)
        	{
        		printf("%d ",Tmp->Key[i]);
        		i++; 
			}
			printf("\n");
        	Tmp = Tmp->Next;
    	}
	
	    return Parent;    
	}        
	return X;
}

static BPlusTree RecursiveInsert(BPlusTree T,KeyType Key,int i,BPlusTree Parent)
{    
	int j,Limit;    
	BPlusTree Sibling; 
	       
	//查找分支     
	j = 0;    
	while (j < T->KeyNum && Key >= T->Key[j])
	{        
		//重复值不插入        
		if (Key == T->Key[j])            
			return T;        
		j++;    
	}    
	if (j != 0 && T->Children[0] != NULL) j--;       //T是一个分支节点 应该插入到j-1孩子中  这是根据这棵二叉树的结构来说的 
	       
	//树叶    
	if (T->Children[0] == NULL)
	{
		T = InsertElement(1, Parent, T, Key, i, j);
		
	}        
		    
	//内部节点     
	else        
		T->Children[j] = RecursiveInsert(T->Children[j], Key, j, T);  
		      
	//先插入节点再进行调整节点        
	Limit = M;        
	if (T->KeyNum > Limit)
	{        
		T = SplitNode(Parent, T, i);
	}
	if (Parent != NULL)  	//不是根节点都需要更新父节点对应位置的值      
		Parent->Key[i] = T->Key[0];            
	return T;
}


//插入 
BPlusTree Insert(BPlusTree T,KeyType Key)
{
    return RecursiveInsert(T, Key, 0, NULL);
}

static void RecursiveTravel(BPlusTree T,int Level,FILE *f){

    int i;
    if (T != NULL){
        fprintf(f,"  ");
        fprintf(f,"[Level:%d]-->",Level);
        fprintf(f,"(");
        i = 0;
        while (i < T->KeyNum)/*  T->Key[i] != Unavailable*/
            fprintf(f,"%d:",T->Key[i++]);
        fprintf(f,")\n");
        Level++;
        i = 0;
        while (i <= T->KeyNum) {
            RecursiveTravel(T->Children[i], Level,f);
            i++;
        }
    }
}

 

/* 遍历 */

extern void Travel(BPlusTree T,FILE *f){
    RecursiveTravel(T, 0,f);
    printf("\n");
}

 

/* 遍历树叶节点的数据 */

extern void TravelData(BPlusTree T,FILE* f,FILE* f1){
    BPlusTree Tmp;
    int i;
    if (T == NULL)
        return ;
    printf("All Data:");
    Tmp = T;
    while (Tmp->Children[0] != NULL)
        Tmp = Tmp->Children[0];
    /* 第一片树叶 */
    while (Tmp != NULL){
    	fprintf(f1,",,,,,,%x\n",Tmp);
        i = 0;
        while (i < Tmp->KeyNum)
            fprintf(f," %d\n",Tmp->Key[i++]);
        Tmp = Tmp->Next;
        
    }

}



int main(int argc, char *argv[]) 
{
	int i,size=10000;

    BPlusTree T;

    T = Initialize();
    
	i = 0;
	
	FILE* f = fopen("t.txt","w");//存储顺序读取结果
	FILE* f1 = fopen("tt.txt","w");//树的每一层结构
	FILE* f2 = fopen("rand.txt","w");//存储每一个随机数
	FILE* ff = fopen("ff.txt","w");//每一个新节点的地址
	//设置种子,最好是默认种子 
	//srand((unsigned int)time(NULL));
    while (i < size)
    {
    	int t = rand();
    	fprintf(f2,"%d\n",t%size);
    	T = Insert(T,t%size);
    	i++;
	}


    TravelData(T,f,ff);
    
	Travel(T,f1);
    
    fclose(f);fclose(f1);fclose(f2);fclose(ff);
	return 0;
}

该代码建造的B+树,父节点中存储的是子节点中的最小值。

  • 使用4叉01基数树完成字符串检索
    按照读取的字符串建立一棵4叉树即可

  • 使用2叉01基数树完成字符串检索
    同理,按照读取的字符串建立一棵2叉树即可

3.多模式字符串匹配

本次实验有三个子实验,

4.网络爬虫+PageRank算法

说实话,这部分内容我并没有做出来,因为临近考试了,我并没有花太多的时间去查一些网络爬虫的知识,而PageRank算法关于不可约的推导没看明白,虽然代码是比着优化后的矩阵写的,能跑出结果来,但是看结果好像不太对,也没有再去调,也欢迎大家提出意见。

发布了13 篇原创文章 · 获赞 15 · 访问量 3453

猜你喜欢

转载自blog.csdn.net/dongtinglu/article/details/103842878
今日推荐