复习
栈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;
}