数据结构第五天————项目(电子词典)

25 篇文章 0 订阅
5 篇文章 0 订阅

复习
栈FILO
顺序栈
只能在一端操作的顺序表,建议在表尾进行入栈和出栈
链式栈
只能在一端操作的链表,建议在表头进行入栈和出栈
队列FIFO
顺序队列
入队和出队分别在两端操作的顺序表
顺序表:表头入队,需要移动元素;表尾出队,很方便。
改进办法:
方案1:空间只用一次,例如:讲义中二叉树的层次遍历
struct queue
{
data_t data[SIZE];
int rear; //表示入队的下标
int front;//表示出队的下标
};
方案2:空间重复利用,即:循环顺序队列
struct queue
{
data_t data[SIZE];
int rear; //表示入队的下标
int front;//表示出队的下标
int count;//计数器,表示当前队列中一共有多少元素
};
链式队列
入队和出队分别在两端操作的链表
链表:入队在表尾,需要找尾结点;出队在表头,很方便。
改进办法:
方案1:特殊的头结点,在头结点中保存首结点的地址和尾结点的地址。
struct queueNode
{
data_t data;
struct queueNode * pNext;
};

			struct queueHead
			{
				struct queueNode * pHead;
				struct queueNode * pTail;
			};
		方案2:已知尾结点的单向循环链表
			struct queueNode
			{
				data_t  data;
				struct queueNode * pNext;
			};

第五天
算法的好坏:
完成任务 稳定性 时间复杂度 空间复杂度 。。。
时间复杂度:
最简单的判断方式
1. 有几重循环
2. 每一重循环和表的大小是否有关
例:自建国以来最严重的一次地震
data_t max = data[0]; int j = 0;
for ( int i = 0; i < n; i++ )
{
if ( max < data[i] )
{
max = data[i]; j = i;
}
}
该算法的时间复杂度就是O(n)
例:顺序表查找
int searchList( LIST * pList, data_t oldData )
{
for ( int i = 0; i < pList->count; i++ )
{
if ( oldData == pList->data[i] )
{
return i;
}
}
return -1;
}
该算法的时间复杂度就是O(n)
例:冒泡排序
for ( int i = 0; i < n - 1; i++ )
{
for ( int j = 0; j < n - 1 - i; j++ )
{

}
}
该算法的时间复杂度就是O(n*n)

查找
	顺序查找(见上面笔记)
	折半查找(二分法查找)
		前提:顺序表中的数据有序。假设从小到大。
		int binarySearch( LIST * pList, data_t data )
		{
			int low = 0;
			int high = pList->count - 1;
			int mid = ( low + high ) / 2;
			
			while ( low <= high )
			{
				mid = ( low + high ) / 2;
				if ( data == pList->data[mid] )
				{
					return mid;
				}
				else if ( data > pList->data[mid] )
				{
					low = mid + 1;
				}
				else 
				{
					high = mid - 1;
				}
			}
			return -1;
		}
		该算法的时间复杂度就是O(log2(n+1))
	分块查找
		笔试题:有可能编程(比例不大),一般是选择题
			例:以下一组序列,找一下有没有68,最少的比较次数是多少次(选择题)
				18 10 9 8 16 20 38 42 19 50 84 72 56 55 76 100 90 88 108 
			例:以下一组序列,设计一个算法,查找指定的数值(编程题)
				18 10 9 8 16 20 38 42 19 50 84 72 56 55 76 100 90 88 108 
			例:以下一组序列,设计一个算法,查找指定的数值(编程题)
				2,3,5,9,3,6,8,12,5,8,13,20,7,9,15,21
	Hash查找
		特点:
			怎么存的就怎么查。
		关键点:
			hash函数的确定
			怎么解决冲突
		思路:
			1. 观察要保存的数据的特点
			2. 定义一个hash函数
			3. 确定一种解决冲突的办法(线性探测法、二次探查法、链地址法)
			4. 通过hash函数给每一个要存储的数据找到合适的位置。
				如果产生冲突,解决冲突。
			5. 查找的时候,通过hash函数确定当前被查找的元素的位置。
				如果该位置为空,没有找到。退出。
				如果该位置有元素,进行比较,不是当前要找的值,表示有冲突,解决冲突,再比较。
	项目
		项目主要让大家学习分析问题,解决问题
		学会:封装接口
		题目:《电子词典》
		功能:查询单词、历史记录、增加、修改... ...
		今天的目标:
			1. 将dictionary.txt中的内容读到内存中
			2. 能实现查询功能
		分析:20000个单词
			顺序查找:太慢了
			折半查找:太慢了
			分块查找:按照单词首字母分块之后,再加上折半查找。
				要求:单词有序。
				如果当前的dictionary.txt无序,先加载到内存,再排序。
			hash查找:适合数据量大一些。
				要保存的数据的特点:
					数量大,由大小写字母和-构成的字符串
					单词44个字符,解释200个字符
				确定hash表,定义一个hash函数
					方案1: 
						首字母从a~z总共26个,每一个单词的长度最多46,按4字节对齐,给48个空间。
						创建26*46这么一个二维数组作hash表,每一个元素是链表的首地址。
						hash函数:行号 = 单词首字母-'a',列号 = 单词长度-1					
				确定一种解决冲突的办法:链地址法
		细化:
			hash表:26*46一个二维数组,可以改为一个26*46空间的一组数组。
			#define ROW  26
			#define COLUMN 26
			#define SIZE (ROW * COLUMN)
			#define WORD_LEN 48
			#define TRANSLATE_LEN 200
			typedef struct 
			{
				char word[WORD_LEN];
				char translate[TRANSLATE_LEN];
			}data_t;
			typedef struct list
			{
				data_t data;
				struct list * pNext;
			}LIST;
			typedef (struct list *)  LIST_T;
			struct list * hashTable[SIZE];
			
			/*
			LIST_T hashTable[SIZE];
			LIST_T * p = hashTable;
			
			int arr[4];
			int * p = arr = &arr[0];
			*/
			
			初始化hash表,hash表中全部为NULL。
			hash函数:
				int hashFunction( const char * word )
				{
					int row = 0;
					int column = 0;
					//先把大写字母改为小写字母,再求行号,行号 = 单词首字母-'a',
					row = ( word[0] | 0x20 ) - 'a'; 
					
					//列号 = 单词长度 - 1
					column = strlen( word ) - 1;
					
					return (row * COLUMN + column);
				}

头文件.h

#ifndef _DICT_H_

#define _DICT_H_



//常量定义

#define ROW  26

#define COLUMN 46

#define SIZE (ROW * COLUMN)

#define WORD_LEN 48

#define TRANSLATE_LEN 256

#define LEN 400



enum menu

{

	SEARCH = 1,

	QUIT = 255,

};

//类型定义 

typedef struct 

{

	char word[WORD_LEN];

	char translate[TRANSLATE_LEN];

}data_t;

typedef struct list

{

	data_t data;

	struct list * pNext;

}LIST;

typedef struct list *  LIST_T;

//函数声明

/*

函数名:createHashTable

函数功能:创建hash表

函数参数:

	int size : hash表的大小

函数返回值:成功时,返回hash表首地址,失败时,返回NULL.

*/

LIST_T * createHashTable( int size );



/*

函数名:distroyHashTable

函数功能:销毁hash表

函数参数:LIST_T * pHash : hash表首地址

	int size: hash表的大小

函数返回值:无

*/

void distroyHashTable( LIST_T * pHash, int size );



/*

函数名:initHashTable

函数功能:把单词存入hash表

函数参数:char * fileName : 将该文件中的单词和解释放入hash表中

	LIST_T * pHash : hash表首地址

	int size: hash表的大小

函数返回值:成功时,返回0,失败时,返回-1.

*/

int initHashTable( const char * fileName, LIST_T * pHash, int size);



/*

函数名:searchWordFromHash

函数功能:从hash表中查询单词

函数参数:

	LIST_T * pHash : hash表首地址

	int size: hash表的大小

	data_t * pData : 保存被查询的单词和查到的解释

函数返回值:成功时,返回0,失败时,返回-1.

*/

int searchWordFromHash( LIST_T * pHash, data_t * pData, int size);



/*

函数名:menu

函数功能:显示菜单//今天只实现查询和退出

函数参数:无

函数返回值:用户选择的功能

*/

int menu();





#endif //_DICT_H_

功能函数.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dict_project.h"
/*
 *
 * 函数名:menu
 *
 * 函数功能:显示菜单//今天只实现查询和退出
 *
 * 函数参数:无
 *
 * 函数返回值:用户选择的功能
 *
 * */

int menu()
{
	int choice = 0;
	printf("******************电子词典********************\n");
	printf("----%d------------查询单词--------------------\n",SEARCH);
	printf("----%d----------退出系统--------------------\n",QUIT);
	printf("***************请输入你的选择******************\n");
	scanf("%d",&choice);
	return choice;
}
//函数声明

/*
 *
 * 函数名:createHashTable
 *
 * 函数功能:创建hash表
 *
 * 函数参数:
 *
 * int size : hash表的大小
 *
 * 函数返回值:成功时,返回hash表首地址,失败时,返回NULL.
 *
 * 	*/

LIST_T * createHashTable( int size )
{
	LIST_T * pHash = NULL;
	pHash = (LIST_T * )malloc( size * sizeof(LIST_T));
	if(NULL != pHash)
	{
		memset(pHash,0,sizeof(LIST_T)*size);
	}
	return pHash;
}
int hashFunction(const char * word)
{
	int row =0;
	int column =0;
	if(!word) return-1;
	//把大写字母转小写,求行号
	row =(word[0] | 0x20)-'a';
	//求列号
	column = strlen (word)-1;
	return (row*COLUMN +column);
}
//字符串分割
void spliteStringByspace(const char *buf,data_t *pData)
{
	int i=0,j=0;
	while( *buf != ' ' && WORD_LEN >i)
	{
		pData->word[i] = *buf;
		i++;
		buf++;
	}
	while(' ' == *buf)
	{
		buf++;
	}
	strncpy(pData->translate,buf,TRANSLATE_LEN);
}
//创建链表节点
LIST *createNode(data_t data)
{
	LIST *pNew=(LIST *)malloc(sizeof(LIST));
	if(NULL !=pNew)
	{
		memset(pNew,0,sizeof(LIST));
		memcpy(&(pNew->data),&data,sizeof(data));
	}
	return pNew;
}
/*
 *
 * 函数名:initHashTable
 *
 * 函数功能:把单词存入hash表
 *
 * 函数参数:char * fileName : 将该文件中的单词和解释放入hash表中
 *
 * LIST_T * pHash : hash表首地址
 *
 * int size: hash表的大小
 *
 * 函数返回值:成功时,返回0,失败时,返回-1.
 *
 * */

int initHashTable( const char * fileName, LIST_T * pHash, int size)
{
	FILE *fp=NULL;
	char *buf=NULL;
	data_t data;
	int index =0;
	LIST*pNew=NULL;
	if( NULL == fileName
	||  NULL == pHash
	||  0    >= size)
	{
		return -1;
	}
	buf=(char *)malloc(sizeof(char)* LEN);
	if(NULL ==buf)
	{
		perror("malloc error");
		return -1;
	}
	//只读方式打开
	fp= fopen(fileName,"r");
	if(NULL == fp)
	{
		perror("file open error");
		return -1;
	}
	//循环
	//读单词和解释
	fgets(buf,LEN,fp);
	while(!feof(fp))
	{
		memset( &data,0,sizeof(data));
		//进行字符串分割,区分单词和解释
		spliteStringByspace(buf,&data); 
		//通过hash函数得到单词存放的下标
		index=hashFunction(data.word);
		if(index >=size||index<0)
		{
			break;
		}
		//创建链表节点
		pNew= createNode(data);
		pNew->pNext=pHash[index];
		pHash[index]=pNew;
		memset( buf,0,LEN);
		fgets(buf,LEN,fp);
		//初始化节点
		//实现链表的插入
	}
	//关闭文件
	fclose(fp);
	//释放文件
	free(buf);
	buf=NULL;
	return 0;
}
//不带头节点的单向不循环链表的查询
int searchList(LIST *pList,data_t *pData)
{
	LIST *p=NULL;
	if(NULL==pList
	|| NULL==pData
	|| 0   == strlen(pData->word))
	{
		return -1;
	}
	p=pList;
	while(NULL !=p)
	{
		if(0== strcmp(p->data.word,pData->word))
		{
			strncpy(pData->translate,p->data.translate,TRANSLATE_LEN);
			return 0;
		}
		p=p->pNext;
	}
	return -1;
}
/*
 *
 * 函数名:searchWordFromHash
 *
 * 函数功能:从hash表中查询单词
 *
 * 函数参数:
 *
 * LIST_T * pHash : hash表首地址
 *
 * int size: hash表的大小
 *
 * data_t * pData : 保存被查询的单词和查到的解释
 *
 * 函数返回值:成功时,返回0,失败时,返回-1.
 *
 * 	*/

int searchWordFromHash( LIST_T * pHash, data_t * pData, int size)
{
	if(NULL==pHash
	|| 0>=size
	|| NULL == pData
	|| 0 == strlen(pData->word))
	{
		return -1;
	}
	int index=hashFunction(pData->word);
	if(index >= size || index<0)
	{
		return -1;
	}
	if(NULL ==pHash[index])
	{
		return -1;
	}
	return searchList(pHash[index],pData);
}
//单向不循环链表的释放
void destroyList(LIST *pList)
{
	LIST *p=NULL;
	if(NULL ==pList)
	{
		return;
	}
	p=pList;
	while(NULL !=p)
	{
		pList=p->pNext;
		free(p);
		p=pList;
	}
}
/*
 *
 * 函数名:distroyHashTable
 *
 * 函数功能:销毁hash表
 *
 * 函数参数:LIST_T * pHash : hash表首地址
 *
 * 	int size: hash表的大小
 *
 * 	函数返回值:无
 *
 * 	*/

void distroyHashTable( LIST_T * pHash, int size )
{
	int i=0;
	if(NULL ==pHash)
	{
		return ;
	}
	for(i=0;i<size;i++)
	{
		destroyList(pHash[i]);
	}
}
/*
 * 函数名:addWordToFile
 * 函数功能:增加单词和解释到文件
 * 函数参数:文件名
 * 函数返回值:写入成功返回0;失败返回-1;
 
int addWordToFile(fileName)
{
	
	fopen(fileName,'a');
	printf("请输入要增加的单词和翻译并用空格隔开:\n");
	scanf("%s",&)
	fwrite()
}*/

测试函数.c

#include <stdio.h>

#include <string.h>

#include "dict_project.h"



int main()

{

	LIST_T * pHash = NULL;

	int choice = 0;

	data_t data;

	

	//创建hash表

	pHash = createHashTable( SIZE );

	if ( NULL == pHash )

	{

		return -1;

	}

	

	//打开文件,把单词和解释存入hash表

	initHashTable( "dict.txt", pHash, SIZE );

	

	while (1)

	{

		choice = menu();

		switch( choice )

		{

			case SEARCH:

				memset( &data, 0, sizeof(data) );

				printf("输入单词\r\n");

				scanf("%s", data.word);

				if ( -1 != searchWordFromHash( pHash, &data, SIZE ))

				{

					printf("单词:%s\t, 解释:%s\r\n", data.word, data.translate);

				}

				else 

				{

					printf("查无此词\r\n");

				}

				break;

			default:

				printf("---bye---bye-- \r\n");

				distroyHashTable( pHash, SIZE );

				return 0;

		}

	}

	return 0;

}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值