mirror of
https://github.com/kangjianwei/Data-Structure.git
synced 2026-02-06 16:31:59 +08:00
💡 KMP算法、关键词索引
This commit is contained in:
7
CLion/CourseBook/0404_KMP/CMakeLists.txt
Normal file
7
CLion/CourseBook/0404_KMP/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(KMP SString.h SString.c KMP.h KMP.c KMP-main.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(KMP Scanf_lib)
|
||||
64
CLion/CourseBook/0404_KMP/KMP-main.c
Normal file
64
CLion/CourseBook/0404_KMP/KMP-main.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "KMP.h" //**▲04 串**//
|
||||
|
||||
// 测试函数,打印字符串
|
||||
void PrintElem(SString S);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char* s = "abaaabcaabaabcacabaabcaabaabcac";
|
||||
char* t = "abaabcac";
|
||||
SString S, T;
|
||||
int* next; // 模式串的next函数值
|
||||
int* nextval; // 模式串的nextval函数值
|
||||
int pos; // 匹配起点
|
||||
int i, j;
|
||||
|
||||
StrAssign(S, s); // 初始化主串
|
||||
printf("S = ");
|
||||
PrintElem(S);
|
||||
|
||||
StrAssign(T, t); // 初始化模式串
|
||||
printf("T = ");
|
||||
PrintElem(T);
|
||||
|
||||
|
||||
// 注:next数组和nextval数组的0号单元是弃用的,从1号单元开始存储有效数据
|
||||
next = (int*) malloc((T[0] + 1) * sizeof(int));
|
||||
nextval = (int*) malloc((T[0] + 1) * sizeof(int));
|
||||
|
||||
get_next(T, next); // 算法4.7
|
||||
get_nextval(T, nextval); // 算法4.8,即算法4.7的改进版
|
||||
|
||||
printf("next : ");
|
||||
for(i = 1; i <= T[0]; i++) {
|
||||
printf("%d", next[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("nextval : ");
|
||||
for(i = 1; i <= T[0]; i++) {
|
||||
printf("%d", nextval[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
|
||||
pos = 1;
|
||||
|
||||
i = Index_KMP(S, T, pos, next);
|
||||
j = Index_KMP(S, T, pos, nextval);
|
||||
|
||||
printf("从%d个字符起,T 在 S 中第一次匹配成功的位置为 %d\n", pos, i);
|
||||
printf("从%d个字符起,T 在 S 中第一次匹配成功的位置为 %d\n", pos, j);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 测试函数,打印字符串
|
||||
void PrintElem(SString S) {
|
||||
int i;
|
||||
|
||||
for(i = 1; i <= S[0]; i++) {
|
||||
printf("%c", S[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
106
CLion/CourseBook/0404_KMP/KMP.c
Normal file
106
CLion/CourseBook/0404_KMP/KMP.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*=======================
|
||||
* KMP算法
|
||||
*
|
||||
* 包含算法: 4.6、4.7、4.8
|
||||
========================*/
|
||||
|
||||
#include "KMP.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.6 ████████
|
||||
*
|
||||
* 查找
|
||||
*
|
||||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||||
* 如果查找成功,返回匹配的位置。
|
||||
*
|
||||
*【注】
|
||||
* 1.该实现用到了KMP算法,是一种比较高效的字符串匹配方式
|
||||
* 2.教材中没有next参数
|
||||
*/
|
||||
int Index_KMP(SString S, SString T, int pos, int next[]) {
|
||||
int i = pos;
|
||||
int j = 1;
|
||||
|
||||
if(pos < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 比较字符串
|
||||
while(i <= S[0] && j <= T[0]) {
|
||||
/*
|
||||
* 两种情形:
|
||||
* 1.在模式串的第一个字符处就失配
|
||||
* 2.主串和模式串处的字符相等
|
||||
*/
|
||||
if(j == 0 || S[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
} else {
|
||||
// 失配时回到前一个适当的位置
|
||||
j = next[j];
|
||||
}
|
||||
}
|
||||
|
||||
if(j > T[0]) {
|
||||
// 匹配成功,返回匹配位置
|
||||
return i - T[0];
|
||||
} else {
|
||||
// 匹配失败
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.7 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
*/
|
||||
void get_next(SString T, int next[]) {
|
||||
int i = 1;
|
||||
int j = 0;
|
||||
|
||||
// 模式串第一个字符处失配时,模式串需要从头比较,主串需要前进到下一个位置比较
|
||||
next[1] = 0;
|
||||
|
||||
// 遍历模式串上的字符
|
||||
while(i < T[0]) {
|
||||
if(j == 0 || T[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
next[i] = j;
|
||||
} else {
|
||||
j = next[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.8 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
* 这是一个优化后的版本,效率较算法4.7有所提高。
|
||||
*/
|
||||
void get_nextval(SString T, int nextval[]) {
|
||||
int i = 1;
|
||||
int j = 0;
|
||||
|
||||
// 模式串第一个字符处失配时,模式串需要从头比较,主串需要前进到下一个位置比较
|
||||
nextval[1] = 0;
|
||||
|
||||
// 遍历模式串上的字符
|
||||
while(i < T[0]) {
|
||||
if(j==0 || T[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
|
||||
if(T[i] != T[j]) {
|
||||
nextval[i] = j;
|
||||
} else {
|
||||
nextval[i] = nextval[j];
|
||||
}
|
||||
} else {
|
||||
j = nextval[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
43
CLion/CourseBook/0404_KMP/KMP.h
Normal file
43
CLion/CourseBook/0404_KMP/KMP.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*=======================
|
||||
* KMP算法
|
||||
*
|
||||
* 包含算法: 4.6、4.7、4.8
|
||||
========================*/
|
||||
|
||||
#ifndef KMP_H
|
||||
#define KMP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "SString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.6 ████████
|
||||
*
|
||||
* 查找
|
||||
*
|
||||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||||
* 如果查找成功,返回匹配的位置。
|
||||
*
|
||||
*【注】
|
||||
* 1.该实现用到了KMP算法,是一种比较高效的字符串匹配方式
|
||||
* 2.教材中没有next参数
|
||||
*/
|
||||
int Index_KMP(SString S, SString T, int pos, int next[]);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.7 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
*/
|
||||
void get_next(SString T, int next[]);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.8 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
* 这是一个优化后的版本,效率较算法4.7有所提高。
|
||||
*/
|
||||
void get_nextval(SString T, int nextval[]);
|
||||
|
||||
#endif
|
||||
33
CLion/CourseBook/0404_KMP/SString.c
Normal file
33
CLion/CourseBook/0404_KMP/SString.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*=============================
|
||||
* 串的定长顺序存储表示(顺序串)
|
||||
*
|
||||
* 包含算法: 4.1、4.2、4.3、4.5
|
||||
==============================*/
|
||||
|
||||
#include "SString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(SString T, const char* chars) {
|
||||
int i, len;
|
||||
|
||||
len = (int) strlen(chars);
|
||||
|
||||
// chars过长
|
||||
if(len > MAXSTRLEN) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
T[0] = len;
|
||||
for(i = 1; i <= len; i++) {
|
||||
T[i] = chars[i - 1];
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
36
CLion/CourseBook/0404_KMP/SString.h
Normal file
36
CLion/CourseBook/0404_KMP/SString.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*=============================
|
||||
* 串的定长顺序存储表示(顺序串)
|
||||
*
|
||||
* 包含算法: 4.1、4.2、4.3、4.5
|
||||
==============================*/
|
||||
|
||||
#ifndef SSTRING_H
|
||||
#define SSTRING_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h> // 提供strlen原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSTRLEN 255 // 顺序串的最大串长
|
||||
|
||||
/*
|
||||
* 串的顺序存储类型定义
|
||||
*
|
||||
* 注:有效元素从SString的1号单元开始存储
|
||||
* SString的0号单元用来存储其长度
|
||||
*/
|
||||
typedef unsigned char SString[MAXSTRLEN + 1]; // 0号单元存放串的长度
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(SString T, const char* chars);
|
||||
|
||||
#endif
|
||||
12
CLion/CourseBook/0405_WordList/CMakeLists.txt
Normal file
12
CLion/CourseBook/0405_WordList/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(WordList ELinkList.h ELinkList.c HString.h HString.c WordList.h WordList.c WordList-main.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(WordList Scanf_lib)
|
||||
|
||||
# 记录要拷贝到*.exe目录下的资源文件
|
||||
file(GLOB TestData TestData*.txt)
|
||||
# 将资源文件拷贝到*.exe目录下,不然无法加载
|
||||
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
95
CLion/CourseBook/0405_WordList/ELinkList.c
Normal file
95
CLion/CourseBook/0405_WordList/ELinkList.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*=======================
|
||||
* 扩展的单链表(线性链表)
|
||||
*
|
||||
* 包含算法: 2.20
|
||||
========================*/
|
||||
|
||||
#include "ELinkList.h" //**▲02 线性表**//
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 内存操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 内存分配
|
||||
*
|
||||
* 为线性链表申请一个结点,并存入指定的数据e。
|
||||
*
|
||||
*【备注】
|
||||
* static修饰的含义是该函数仅限当前文件内使用
|
||||
*/
|
||||
Status MakeNode(Link* p, ElemType e) {
|
||||
if(p == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 申请空间
|
||||
*p = (Link) malloc(sizeof(LNode));
|
||||
if(*p == NULL) {
|
||||
// 这里没有退出程序,而是返回错误提示
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
(*p)->data = e;
|
||||
(*p)->next = NULL;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表常规操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(ELinkList* L) {
|
||||
Link p;
|
||||
|
||||
if(L == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 创建头结点
|
||||
p = (Link) malloc(sizeof(LNode));
|
||||
if(p == NULL) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
p->next = NULL;
|
||||
|
||||
// 只有头结点时,首位游标指向自身
|
||||
(*L).head = (*L).tail = p;
|
||||
(*L).len = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表扩展操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 向尾部添加
|
||||
*
|
||||
* 将s所指的一串结点链接在链表L后面
|
||||
*/
|
||||
Status Append(ELinkList* L, Link s) {
|
||||
int count;
|
||||
|
||||
if(L == NULL || (*L).head == NULL || s == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
(*L).tail->next = s;
|
||||
|
||||
// 确定新的尾结点位置
|
||||
while(s != NULL) {
|
||||
(*L).tail = s;
|
||||
s = s->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
(*L).len += count;
|
||||
|
||||
return OK;
|
||||
}
|
||||
75
CLion/CourseBook/0405_WordList/ELinkList.h
Normal file
75
CLion/CourseBook/0405_WordList/ELinkList.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*=======================
|
||||
* 扩展的单链表(线性链表)
|
||||
*
|
||||
* 包含算法: 2.20
|
||||
========================*/
|
||||
|
||||
#ifndef ELINKLIST_H
|
||||
#define ELINKLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include <limits.h> // 提供一些极限常量
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/*
|
||||
* ████ 注意 ████
|
||||
*
|
||||
* 教材中的线性链表命名为LinkList,
|
||||
* 这里为了与单链表区分,故将其命名为ELinkList。
|
||||
* 线性链表可以理解成对普通链表的一种扩展。
|
||||
*/
|
||||
|
||||
/* 线性链表元素类型定义 */
|
||||
typedef int ElemType;
|
||||
|
||||
/*
|
||||
* 线性链表结构
|
||||
*
|
||||
* 注:这里的线性链表存在头结点
|
||||
*/
|
||||
typedef struct LNode {
|
||||
ElemType data;
|
||||
struct LNode* next;
|
||||
} LNode, * Link, * Position;
|
||||
|
||||
/* 维护线性链表头尾指针及长度信息 */
|
||||
typedef struct {
|
||||
Link head, tail; // 分别指向线性链表中的头结点和尾结点
|
||||
int len; // 指示线性链表中数据元素的个数
|
||||
} ELinkList;
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 内存操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 内存分配
|
||||
*
|
||||
* 为线性链表申请一个结点,并存入指定的数据e。
|
||||
*
|
||||
*【备注】
|
||||
* static修饰的含义是该函数仅限当前文件内使用
|
||||
*/
|
||||
Status MakeNode(Link* p, ElemType e);
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表常规操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(ELinkList* L);
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表扩展操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 向尾部添加
|
||||
*
|
||||
* 将s所指的一串结点链接在链表L后面
|
||||
*/
|
||||
Status Append(ELinkList* L, Link s);
|
||||
|
||||
#endif
|
||||
95
CLion/CourseBook/0405_WordList/HString.c
Normal file
95
CLion/CourseBook/0405_WordList/HString.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*=========================
|
||||
* 串的堆分配存储表示(堆串)
|
||||
*
|
||||
* 包含算法: 4.4
|
||||
==========================*/
|
||||
|
||||
#include "HString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(HString* T, const char* chars) {
|
||||
int i, j;
|
||||
|
||||
// 求chars的长度
|
||||
i = (int) strlen(chars);
|
||||
|
||||
// 没有有效元素
|
||||
if(i == 0) {
|
||||
(*T).ch = NULL;
|
||||
(*T).length = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 存在有效元素时,需要分配存储空间
|
||||
(*T).ch = (char*) malloc(i * sizeof(char));
|
||||
if(!((*T).ch)) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
for(j = 0; j < i; j++) {
|
||||
(*T).ch[j] = chars[j];
|
||||
}
|
||||
|
||||
(*T).length = i;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 比较
|
||||
*
|
||||
* 比较串S和串T,返回比较结果。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrCompare(HString S, HString T) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < S.length && i < T.length; i++) {
|
||||
// 遇到不同的字符时,比较其大小
|
||||
if(S.ch[i] != T.ch[i]) {
|
||||
return S.ch[i] - T.ch[i];
|
||||
}
|
||||
}
|
||||
|
||||
return S.length - T.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* 复制
|
||||
*
|
||||
* 将串S复制到串T。
|
||||
*/
|
||||
Status StrCopy(HString* T, HString S) {
|
||||
int i;
|
||||
|
||||
if(S.length == 0) {
|
||||
(*T).ch = NULL;
|
||||
(*T).length = 0;
|
||||
} else {
|
||||
// 分配空间
|
||||
(*T).ch = (char*) malloc(S.length * sizeof(char));
|
||||
if(!(*T).ch) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
// 复制元素
|
||||
for(i = 0; i < S.length; i++) {
|
||||
(*T).ch[i] = S.ch[i];
|
||||
}
|
||||
|
||||
// 复制长度信息
|
||||
(*T).length = S.length;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
53
CLion/CourseBook/0405_WordList/HString.h
Normal file
53
CLion/CourseBook/0405_WordList/HString.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*=========================
|
||||
* 串的堆分配存储表示(堆串)
|
||||
*
|
||||
* 包含算法: 4.4
|
||||
==========================*/
|
||||
|
||||
#ifndef HSTRING
|
||||
#define HSTRING
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include <string.h> // 提供strlen原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/*
|
||||
* 串的堆存储表示
|
||||
*
|
||||
* 注:有效元素从ch的0号单元开始存储
|
||||
*/
|
||||
typedef struct {
|
||||
char* ch; // 若是非空串,则按串长分配存储区,否则ch为NULL
|
||||
int length;
|
||||
} HString;
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(HString* T, const char* chars);
|
||||
|
||||
/*
|
||||
* 比较
|
||||
*
|
||||
* 比较串S和串T,返回比较结果。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrCompare(HString S, HString T);
|
||||
|
||||
/*
|
||||
* 复制
|
||||
*
|
||||
* 将串S复制到串T。
|
||||
*/
|
||||
Status StrCopy(HString* T, HString S);
|
||||
|
||||
#endif
|
||||
7
CLion/CourseBook/0405_WordList/TestData.txt
Normal file
7
CLion/CourseBook/0405_WordList/TestData.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
书 号 书 名
|
||||
005 Computer Data Structures
|
||||
010 Introduction to Data Structures
|
||||
023 Fundamentals of Data Structures
|
||||
034 The Design and Analysis of Computer Algorithms
|
||||
050 Introduction to Numerical Analysis
|
||||
067 Numerical Analysis
|
||||
27
CLion/CourseBook/0405_WordList/WordList-main.c
Normal file
27
CLion/CourseBook/0405_WordList/WordList-main.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <stdio.h> // 提供system原型
|
||||
#include "WordList.h" //**▲04 串**//
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
FILE* fp;
|
||||
char line[MaxLineLen];
|
||||
|
||||
char* bookinfo = "TestData.txt"; // 书目文件名
|
||||
char* bookidx = "BookIdx.txt"; // 关键词索引文件名
|
||||
|
||||
// 创建索引表
|
||||
Main(bookinfo, bookidx);
|
||||
|
||||
// 显示索引表到屏幕
|
||||
if((fp = fopen(bookidx, "r"))!=NULL) {
|
||||
printf("---------索引表生成功!---------\n\n");
|
||||
|
||||
while(feof(fp)==FALSE) {
|
||||
fgets(line, MaxLineLen, fp);
|
||||
printf("%s", line);
|
||||
}
|
||||
} else {
|
||||
printf("---------未发现索引表!---------\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
308
CLion/CourseBook/0405_WordList/WordList.c
Normal file
308
CLion/CourseBook/0405_WordList/WordList.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*===========================================
|
||||
* 索引表
|
||||
*
|
||||
* 包含算法: 4.9、4.10、4.11、4.12、4.13、4.14
|
||||
============================================*/
|
||||
|
||||
#include "WordList.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.9 ████████
|
||||
*
|
||||
* 从文件bookinfo中读取书目信息,并依此创建相应的关键词索引表,然后将索引表写入文件bookidx。
|
||||
*/
|
||||
void Main(char* bookinfo, char* bookidx) {
|
||||
FILE* f, * g;
|
||||
char head[MaxLineLen]; // 书目的表头信息(未使用)
|
||||
IdxListType idxlist; // 关键词索引表
|
||||
ElemType bno; // 书号
|
||||
int count;
|
||||
|
||||
// 以“只读”模式打开书目文件
|
||||
if((f = fopen(bookinfo, "r")) != NULL) {
|
||||
|
||||
// 以“只写”模式打开索引文件
|
||||
if((g = fopen(bookidx, "w")) != NULL) {
|
||||
|
||||
// 初始化索引表
|
||||
InitIdxList(&idxlist);
|
||||
|
||||
// 跳过文件第一行
|
||||
fgets(head, MaxLineLen, f);
|
||||
|
||||
count = 0;
|
||||
|
||||
// 如果未到文件结尾,则一直读文件
|
||||
while(feof(f) == FALSE && count < MaxBookNum) {
|
||||
|
||||
// 从文件f读入一个书目信息到书目缓冲区gBuf
|
||||
GetLine(f);
|
||||
|
||||
// 从gBuf提取关键词到词表gWdList,书号存入bno
|
||||
ExtractKeyWord(&bno);
|
||||
|
||||
// 将书号及对应的关键词插入索引表idxlist
|
||||
InsIdxList(&idxlist, bno);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
// 向文件g中写入索引表数据
|
||||
PutText(g, idxlist);
|
||||
|
||||
fclose(g);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 初始化索引表
|
||||
*
|
||||
*【注】
|
||||
* 教材中将索引表表头置为空串,但这里设定了一个有意义的表头
|
||||
*/
|
||||
void InitIdxList(IdxListType* idxlist) {
|
||||
// 索引表的表头信息
|
||||
char* chars = "关键词 书号索引";
|
||||
IdxTermType e;
|
||||
|
||||
// 初始化表头信息
|
||||
StrAssign(&(e.key), chars);
|
||||
|
||||
// 初始化书号索引链表
|
||||
InitList(&(e.bnolist));
|
||||
|
||||
(*idxlist).item[0] = e;
|
||||
|
||||
// 表头为第0条信息
|
||||
(*idxlist).last = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 从文件f中读取一条书目信息存入书目缓冲区gBuf。
|
||||
*/
|
||||
void GetLine(FILE* f) {
|
||||
// 读取一行数据,存入缓冲区gBuf
|
||||
fgets(gBuf, MaxLineLen, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* 从缓冲区gBuf中提取书名关键词到词表gWdList,书号存入bno。
|
||||
*/
|
||||
void ExtractKeyWord(ElemType* bno) {
|
||||
char delim[] = {'-', ' ', '\r', '\n', '\t'}; // 分隔符
|
||||
char* title; // 书名
|
||||
char* token; // 从书名中分解出的关键词
|
||||
|
||||
// 分解书目字符串,将书号存入bno(十进制),并用title指向剩下的字符串(书名)
|
||||
*bno = (int) strtol(gBuf, &title, 10);
|
||||
|
||||
// 将书名的由大写变小写
|
||||
strlwr(title);
|
||||
|
||||
// 清空关键词词表
|
||||
gWdList.last = 0;
|
||||
|
||||
// 分解关键词
|
||||
for(token = strtok(title, delim); token != NULL; token = strtok(NULL, delim)) {
|
||||
// 如果该关键词是常用词,则忽略它
|
||||
if(isCommonWords(token) == TRUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 记下从书名中提取的关键词
|
||||
gWdList.item[gWdList.last++] = token;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.10 ████████
|
||||
*
|
||||
* 将书号bno对应的书名中的关键词按词典顺序插入到索引表idxlist。
|
||||
*/
|
||||
Status InsIdxList(IdxListType* idxlist, int bno) {
|
||||
int i, j;
|
||||
Boolean boo;
|
||||
HString wd;
|
||||
|
||||
if(gWdList.last <= 0) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 遍历书号bno对应的书名中的所有关键词
|
||||
for(i = 0; i < gWdList.last; i++) {
|
||||
// 获取待插入的关键词
|
||||
GetWord(i, &wd);
|
||||
|
||||
// 判断该关键词是否已经位于索引表中
|
||||
j = Locate(*idxlist, wd, &boo);
|
||||
|
||||
// 如果该关键词不在索引表中,则需要插入关键词
|
||||
if(boo == FALSE) {
|
||||
// 将关键词wd插入到索引表
|
||||
InsertNewKey(idxlist, j, wd);
|
||||
}
|
||||
|
||||
// 在关键词已存在的情形下,插入书号
|
||||
if(!InsertBook(idxlist, j, bno)) {
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.11 ████████
|
||||
*
|
||||
* 用wd返回词表gWdList中第i个关键词。
|
||||
*/
|
||||
void GetWord(int i, HString* wd) {
|
||||
if(i < 0 || i > gWdList.last - 1) {
|
||||
StrAssign(wd, "");
|
||||
} else {
|
||||
StrAssign(wd, gWdList.item[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.12 ████████
|
||||
*
|
||||
* 查询在索引表idxlist中是否存在与wd相等的关键词。
|
||||
* 若存在,则返回wd在词表中的位置,并置b为TRUE。
|
||||
* 若不存在,则返回wd应插入的位置,并置b为FALSE。
|
||||
*/
|
||||
int Locate(IdxListType idxlist, HString wd, Boolean* b) {
|
||||
int i, m = -1;
|
||||
|
||||
/*
|
||||
* 在索引表idxlist中查找关键词wd是否存在
|
||||
* 注:0号单元存储了表头信息
|
||||
*/
|
||||
for(i = idxlist.last; i > 0 && (m = StrCompare(idxlist.item[i].key, wd)) > 0; i--) {
|
||||
}
|
||||
|
||||
// 如果找到了关键词wd
|
||||
if(m == 0) {
|
||||
*b = TRUE;
|
||||
return i;
|
||||
} else {
|
||||
*b = FALSE;
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.13 ████████
|
||||
*
|
||||
* 在索引表的索引i(>=0)处插入关键词wd,并初始化书号索引的链表为空表。
|
||||
*/
|
||||
void InsertNewKey(IdxListType* idxlist, int i, HString wd) {
|
||||
int j;
|
||||
|
||||
/*
|
||||
* 索引项后移
|
||||
* 注:0号单元存储了表头信息
|
||||
*/
|
||||
for(j = (*idxlist).last; j >= i; j--) {
|
||||
(*idxlist).item[j + 1] = (*idxlist).item[j];
|
||||
}
|
||||
|
||||
// 插入索引项
|
||||
StrCopy(&((*idxlist).item[i].key), wd);
|
||||
|
||||
// 初始化书号索引链表
|
||||
InitList(&((*idxlist).item[i].bnolist));
|
||||
|
||||
// 索引数目增一
|
||||
(*idxlist).last++;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.14 ████████
|
||||
*
|
||||
* 为索引表在索引i(>0)处的关键词插入书号。
|
||||
*/
|
||||
Status InsertBook(IdxListType* idxlist, int i, ElemType bno) {
|
||||
Link p;
|
||||
|
||||
// 内存分配失败
|
||||
if(MakeNode(&p, bno) == FALSE) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 插入新的书号索引
|
||||
Append(&((*idxlist).item[i].bnolist), p);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 将生成的索引表idxlist输出到文件g。
|
||||
*/
|
||||
void PutText(FILE* g, IdxListType idxlist) {
|
||||
int i, j, m, n;
|
||||
Link p;
|
||||
HString S;
|
||||
ELinkList L;
|
||||
|
||||
if(idxlist.last <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先输出表头信息
|
||||
S = idxlist.item[0].key;
|
||||
for(m = 0; m < S.length; m++) {
|
||||
fprintf(g, "%c", S.ch[m]);
|
||||
}
|
||||
fprintf(g, "\n");
|
||||
|
||||
// 输出索引信息
|
||||
for(i = 1; i <= idxlist.last; i++) {
|
||||
// 1.输出关键词
|
||||
S = idxlist.item[i].key;
|
||||
for(m = 0; m < S.length; m++) {
|
||||
fprintf(g, "%c", S.ch[m]);
|
||||
}
|
||||
|
||||
// 2.输出空格
|
||||
for(j = 1; j <= 18 - idxlist.item[i].key.length; j++) {
|
||||
fprintf(g, " ");
|
||||
}
|
||||
|
||||
// 3.输出书号索引
|
||||
L = idxlist.item[i].bnolist;
|
||||
for(n = 1, p = L.head->next; n <= L.len; n++) {
|
||||
fprintf(g, "%03d", p->data);
|
||||
p = p->next;
|
||||
if(p) {
|
||||
fprintf(g, ",");
|
||||
}
|
||||
}
|
||||
|
||||
// 4.输出换行
|
||||
fprintf(g, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 判断str是否为常用词
|
||||
static Status isCommonWords(char* str) {
|
||||
int i;
|
||||
|
||||
// 常用词词表,这些词汇会被排除在关键词之外
|
||||
WordListType words = {{"a", "an", "the", "of", "and", "is", "to", "as", "in", "for"}, 10};
|
||||
|
||||
// 查询常用词词表
|
||||
for(i = 0; i < words.last; i++) {
|
||||
// 对两字符串进行忽略大小写的比较
|
||||
if(strcasecmp(str, words.item[i]) == 0) {
|
||||
// 如果该字符串是常用词,则返回TRUE
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
130
CLion/CourseBook/0405_WordList/WordList.h
Normal file
130
CLion/CourseBook/0405_WordList/WordList.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*===========================================
|
||||
* 索引表
|
||||
*
|
||||
* 包含算法: 4.9、4.10、4.11、4.12、4.13、4.14
|
||||
============================================*/
|
||||
|
||||
#ifndef WORDLIST_H
|
||||
#define WORDLIST_H
|
||||
|
||||
#include <stdio.h> // 提供fopen、fclose、feof、fgets原型
|
||||
#include <stdlib.h> // 提供exit、strtol原型
|
||||
#include <string.h> // 提供strlen、strcmpi、strlwr原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
#include "ELinkList.h" //**▲02 线性表**//
|
||||
#include "HString.h" //**▲04 串**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define MaxBookNum 1000 // 允许的最大书目数(假设最多只对1000本书建索引表)
|
||||
#define MaxKeyNum 2500 // 索引表最大容量(索引项数量的最大值)
|
||||
#define MaxLineLen 500 // 书目串(行)的最大长度
|
||||
#define MaxWordNum 100 // 词表的最大容量
|
||||
|
||||
/* 类型定义 */
|
||||
|
||||
// 布尔类型
|
||||
typedef Status Boolean;
|
||||
|
||||
// 词表类型(顺序表)
|
||||
typedef struct {
|
||||
char* item[MaxWordNum]; // 词表集合
|
||||
int last; // 词表的长度
|
||||
} WordListType;
|
||||
|
||||
// 索引项类型(索引表的行)
|
||||
typedef struct {
|
||||
HString key; // 关键词
|
||||
ELinkList bnolist; // 存放书号索引的链表
|
||||
} IdxTermType;
|
||||
|
||||
/*
|
||||
* 索引表类型
|
||||
*
|
||||
*【注】
|
||||
* 0号单元存储表头信息,这一点与教材有所不同
|
||||
*/
|
||||
typedef struct {
|
||||
IdxTermType item[MaxKeyNum + 1]; // 索引项的集合
|
||||
int last; // 索引表中包含的索引项数目
|
||||
} IdxListType;
|
||||
|
||||
/* 全局变量(变量名称前面都加了g标记) */
|
||||
|
||||
// 书目缓存区
|
||||
char gBuf[MaxLineLen];
|
||||
|
||||
// 关键词词表(普通词表),已经排除了常用词
|
||||
WordListType gWdList;
|
||||
|
||||
|
||||
/*
|
||||
* ████████ 算法4.9 ████████
|
||||
*
|
||||
* 从文件bookinfo中读取书目信息,并依此创建相应的关键词索引表,然后将索引表写入文件bookidx。
|
||||
*/
|
||||
void Main(char* bookinfo, char* bookidx);
|
||||
|
||||
/*
|
||||
* 初始化索引表
|
||||
*
|
||||
*【注】
|
||||
* 教材中将索引表表头置为空串,但这里设定了一个有意义的表头
|
||||
*/
|
||||
void InitIdxList(IdxListType* idxlist);
|
||||
|
||||
/*
|
||||
* 从文件f中读取一条书目信息存入书目缓冲区gBuf。
|
||||
*/
|
||||
void GetLine(FILE* f);
|
||||
|
||||
/*
|
||||
* 从缓冲区gBuf中提取书名关键词到词表gWdList,书号存入bno。
|
||||
*/
|
||||
void ExtractKeyWord(ElemType* bno);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.10 ████████
|
||||
*
|
||||
* 将书号bno对应的书名关键词按词典顺序插入到索引表idxlist。
|
||||
*/
|
||||
Status InsIdxList(IdxListType* idxlist, int bno);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.11 ████████
|
||||
*
|
||||
* 用wd返回词表gWdList中第i个关键词。
|
||||
*/
|
||||
void GetWord(int i, HString* wd);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.12 ████████
|
||||
*
|
||||
* 查询在索引表idxlist中是否存在与wd相等的关键词。
|
||||
* 若存在,则返回wd在词表中的位置,并置b为TRUE。
|
||||
* 若不存在,则返回wd应插入的位置,并置b为FALSE。
|
||||
*/
|
||||
int Locate(IdxListType idxlist, HString wd, Boolean* b);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.13 ████████
|
||||
*
|
||||
* 在索引表的索引i(>=0)处插入关键词wd,并初始化书号索引的链表为空表。
|
||||
*/
|
||||
void InsertNewKey(IdxListType* idxlist, int i, HString wd);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.14 ████████
|
||||
*
|
||||
* 为索引表在索引i(>0)处的关键词插入书号。
|
||||
*/
|
||||
Status InsertBook(IdxListType* idxlist, int i, int bno);
|
||||
|
||||
/*
|
||||
* 将生成的索引表idxlist输出到文件g。
|
||||
*/
|
||||
void PutText(FILE* g, IdxListType idxlist);
|
||||
|
||||
// 判断str是否为常用词
|
||||
static Status isCommonWords(char* str);
|
||||
|
||||
#endif
|
||||
@@ -23,3 +23,5 @@ add_subdirectory(0309_BankQueuing)
|
||||
add_subdirectory(0401_SString)
|
||||
add_subdirectory(0402_HString)
|
||||
add_subdirectory(0403_LString)
|
||||
add_subdirectory(0404_KMP)
|
||||
add_subdirectory(0405_WordList)
|
||||
|
||||
64
Dev-C++/CourseBook/0404_KMP/KMP-main.cpp
Normal file
64
Dev-C++/CourseBook/0404_KMP/KMP-main.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "KMP.h" //**▲04 串**//
|
||||
|
||||
// 测试函数,打印字符串
|
||||
void PrintElem(SString S);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char* s = "abaaabcaabaabcacabaabcaabaabcac";
|
||||
char* t = "abaabcac";
|
||||
SString S, T;
|
||||
int* next; // 模式串的next函数值
|
||||
int* nextval; // 模式串的nextval函数值
|
||||
int pos; // 匹配起点
|
||||
int i, j;
|
||||
|
||||
StrAssign(S, s); // 初始化主串
|
||||
printf("S = ");
|
||||
PrintElem(S);
|
||||
|
||||
StrAssign(T, t); // 初始化模式串
|
||||
printf("T = ");
|
||||
PrintElem(T);
|
||||
|
||||
|
||||
// 注:next数组和nextval数组的0号单元是弃用的,从1号单元开始存储有效数据
|
||||
next = (int*) malloc((T[0] + 1) * sizeof(int));
|
||||
nextval = (int*) malloc((T[0] + 1) * sizeof(int));
|
||||
|
||||
get_next(T, next); // 算法4.7
|
||||
get_nextval(T, nextval); // 算法4.8,即算法4.7的改进版
|
||||
|
||||
printf("next : ");
|
||||
for(i = 1; i <= T[0]; i++) {
|
||||
printf("%d", next[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("nextval : ");
|
||||
for(i = 1; i <= T[0]; i++) {
|
||||
printf("%d", nextval[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
|
||||
pos = 1;
|
||||
|
||||
i = Index_KMP(S, T, pos, next);
|
||||
j = Index_KMP(S, T, pos, nextval);
|
||||
|
||||
printf("从%d个字符起,T 在 S 中第一次匹配成功的位置为 %d\n", pos, i);
|
||||
printf("从%d个字符起,T 在 S 中第一次匹配成功的位置为 %d\n", pos, j);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 测试函数,打印字符串
|
||||
void PrintElem(SString S) {
|
||||
int i;
|
||||
|
||||
for(i = 1; i <= S[0]; i++) {
|
||||
printf("%c", S[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
106
Dev-C++/CourseBook/0404_KMP/KMP.cpp
Normal file
106
Dev-C++/CourseBook/0404_KMP/KMP.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/*=======================
|
||||
* KMP算法
|
||||
*
|
||||
* 包含算法: 4.6、4.7、4.8
|
||||
========================*/
|
||||
|
||||
#include "KMP.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.6 ████████
|
||||
*
|
||||
* 查找
|
||||
*
|
||||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||||
* 如果查找成功,返回匹配的位置。
|
||||
*
|
||||
*【注】
|
||||
* 1.该实现用到了KMP算法,是一种比较高效的字符串匹配方式
|
||||
* 2.教材中没有next参数
|
||||
*/
|
||||
int Index_KMP(SString S, SString T, int pos, int next[]) {
|
||||
int i = pos;
|
||||
int j = 1;
|
||||
|
||||
if(pos < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 比较字符串
|
||||
while(i <= S[0] && j <= T[0]) {
|
||||
/*
|
||||
* 两种情形:
|
||||
* 1.在模式串的第一个字符处就失配
|
||||
* 2.主串和模式串处的字符相等
|
||||
*/
|
||||
if(j == 0 || S[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
} else {
|
||||
// 失配时回到前一个适当的位置
|
||||
j = next[j];
|
||||
}
|
||||
}
|
||||
|
||||
if(j > T[0]) {
|
||||
// 匹配成功,返回匹配位置
|
||||
return i - T[0];
|
||||
} else {
|
||||
// 匹配失败
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.7 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
*/
|
||||
void get_next(SString T, int next[]) {
|
||||
int i = 1;
|
||||
int j = 0;
|
||||
|
||||
// 模式串第一个字符处失配时,模式串需要从头比较,主串需要前进到下一个位置比较
|
||||
next[1] = 0;
|
||||
|
||||
// 遍历模式串上的字符
|
||||
while(i < T[0]) {
|
||||
if(j == 0 || T[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
next[i] = j;
|
||||
} else {
|
||||
j = next[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.8 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
* 这是一个优化后的版本,效率较算法4.7有所提高。
|
||||
*/
|
||||
void get_nextval(SString T, int nextval[]) {
|
||||
int i = 1;
|
||||
int j = 0;
|
||||
|
||||
// 模式串第一个字符处失配时,模式串需要从头比较,主串需要前进到下一个位置比较
|
||||
nextval[1] = 0;
|
||||
|
||||
// 遍历模式串上的字符
|
||||
while(i < T[0]) {
|
||||
if(j==0 || T[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
|
||||
if(T[i] != T[j]) {
|
||||
nextval[i] = j;
|
||||
} else {
|
||||
nextval[i] = nextval[j];
|
||||
}
|
||||
} else {
|
||||
j = nextval[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Dev-C++/CourseBook/0404_KMP/KMP.dev
Normal file
102
Dev-C++/CourseBook/0404_KMP/KMP.dev
Normal file
@@ -0,0 +1,102 @@
|
||||
[Project]
|
||||
FileName=KMP.dev
|
||||
Name=KMP
|
||||
Type=1
|
||||
Ver=2
|
||||
ObjFiles=
|
||||
Includes=
|
||||
Libs=
|
||||
PrivateResource=
|
||||
ResourceIncludes=
|
||||
MakeIncludes=
|
||||
Compiler=
|
||||
CppCompiler=
|
||||
Linker=
|
||||
IsCpp=0
|
||||
Icon=
|
||||
ExeOutput=
|
||||
ObjectOutput=
|
||||
LogOutput=
|
||||
LogOutputEnabled=0
|
||||
OverrideOutput=0
|
||||
OverrideOutputName=
|
||||
HostApplication=
|
||||
UseCustomMakefile=0
|
||||
CustomMakefile=
|
||||
CommandLine=
|
||||
Folders=
|
||||
IncludeVersionInfo=0
|
||||
SupportXPThemes=0
|
||||
CompilerSet=1
|
||||
CompilerSettings=0000000000000000001000000
|
||||
UnitCount=5
|
||||
|
||||
[VersionInfo]
|
||||
Major=1
|
||||
Minor=0
|
||||
Release=0
|
||||
Build=0
|
||||
LanguageID=1033
|
||||
CharsetID=1252
|
||||
CompanyName=
|
||||
FileVersion=
|
||||
FileDescription=Developed using the Dev-C++ IDE
|
||||
InternalName=
|
||||
LegalCopyright=
|
||||
LegalTrademarks=
|
||||
OriginalFilename=
|
||||
ProductName=
|
||||
ProductVersion=
|
||||
AutoIncBuildNr=0
|
||||
SyncProduct=1
|
||||
|
||||
[Unit3]
|
||||
FileName=KMP-main.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit1]
|
||||
FileName=KMP.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit4]
|
||||
FileName=SString.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit2]
|
||||
FileName=KMP.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit5]
|
||||
FileName=SString.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
43
Dev-C++/CourseBook/0404_KMP/KMP.h
Normal file
43
Dev-C++/CourseBook/0404_KMP/KMP.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*=======================
|
||||
* KMP算法
|
||||
*
|
||||
* 包含算法: 4.6、4.7、4.8
|
||||
========================*/
|
||||
|
||||
#ifndef KMP_H
|
||||
#define KMP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "SString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.6 ████████
|
||||
*
|
||||
* 查找
|
||||
*
|
||||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||||
* 如果查找成功,返回匹配的位置。
|
||||
*
|
||||
*【注】
|
||||
* 1.该实现用到了KMP算法,是一种比较高效的字符串匹配方式
|
||||
* 2.教材中没有next参数
|
||||
*/
|
||||
int Index_KMP(SString S, SString T, int pos, int next[]);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.7 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
*/
|
||||
void get_next(SString T, int next[]);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.8 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
* 这是一个优化后的版本,效率较算法4.7有所提高。
|
||||
*/
|
||||
void get_nextval(SString T, int nextval[]);
|
||||
|
||||
#endif
|
||||
33
Dev-C++/CourseBook/0404_KMP/SString.cpp
Normal file
33
Dev-C++/CourseBook/0404_KMP/SString.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*=============================
|
||||
* 串的定长顺序存储表示(顺序串)
|
||||
*
|
||||
* 包含算法: 4.1、4.2、4.3、4.5
|
||||
==============================*/
|
||||
|
||||
#include "SString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(SString T, const char* chars) {
|
||||
int i, len;
|
||||
|
||||
len = (int) strlen(chars);
|
||||
|
||||
// chars过长
|
||||
if(len > MAXSTRLEN) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
T[0] = len;
|
||||
for(i = 1; i <= len; i++) {
|
||||
T[i] = chars[i - 1];
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
36
Dev-C++/CourseBook/0404_KMP/SString.h
Normal file
36
Dev-C++/CourseBook/0404_KMP/SString.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*=============================
|
||||
* 串的定长顺序存储表示(顺序串)
|
||||
*
|
||||
* 包含算法: 4.1、4.2、4.3、4.5
|
||||
==============================*/
|
||||
|
||||
#ifndef SSTRING_H
|
||||
#define SSTRING_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h> // 提供strlen原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSTRLEN 255 // 顺序串的最大串长
|
||||
|
||||
/*
|
||||
* 串的顺序存储类型定义
|
||||
*
|
||||
* 注:有效元素从SString的1号单元开始存储
|
||||
* SString的0号单元用来存储其长度
|
||||
*/
|
||||
typedef unsigned char SString[MAXSTRLEN + 1]; // 0号单元存放串的长度
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(SString T, const char* chars);
|
||||
|
||||
#endif
|
||||
95
Dev-C++/CourseBook/0405_WordList/ELinkList.cpp
Normal file
95
Dev-C++/CourseBook/0405_WordList/ELinkList.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*=======================
|
||||
* 扩展的单链表(线性链表)
|
||||
*
|
||||
* 包含算法: 2.20
|
||||
========================*/
|
||||
|
||||
#include "ELinkList.h" //**▲02 线性表**//
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 内存操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 内存分配
|
||||
*
|
||||
* 为线性链表申请一个结点,并存入指定的数据e。
|
||||
*
|
||||
*【备注】
|
||||
* static修饰的含义是该函数仅限当前文件内使用
|
||||
*/
|
||||
Status MakeNode(Link* p, ElemType e) {
|
||||
if(p == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 申请空间
|
||||
*p = (Link) malloc(sizeof(LNode));
|
||||
if(*p == NULL) {
|
||||
// 这里没有退出程序,而是返回错误提示
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
(*p)->data = e;
|
||||
(*p)->next = NULL;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表常规操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(ELinkList* L) {
|
||||
Link p;
|
||||
|
||||
if(L == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 创建头结点
|
||||
p = (Link) malloc(sizeof(LNode));
|
||||
if(p == NULL) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
p->next = NULL;
|
||||
|
||||
// 只有头结点时,首位游标指向自身
|
||||
(*L).head = (*L).tail = p;
|
||||
(*L).len = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表扩展操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 向尾部添加
|
||||
*
|
||||
* 将s所指的一串结点链接在链表L后面
|
||||
*/
|
||||
Status Append(ELinkList* L, Link s) {
|
||||
int count;
|
||||
|
||||
if(L == NULL || (*L).head == NULL || s == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
(*L).tail->next = s;
|
||||
|
||||
// 确定新的尾结点位置
|
||||
while(s != NULL) {
|
||||
(*L).tail = s;
|
||||
s = s->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
(*L).len += count;
|
||||
|
||||
return OK;
|
||||
}
|
||||
75
Dev-C++/CourseBook/0405_WordList/ELinkList.h
Normal file
75
Dev-C++/CourseBook/0405_WordList/ELinkList.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*=======================
|
||||
* 扩展的单链表(线性链表)
|
||||
*
|
||||
* 包含算法: 2.20
|
||||
========================*/
|
||||
|
||||
#ifndef ELINKLIST_H
|
||||
#define ELINKLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include <limits.h> // 提供一些极限常量
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/*
|
||||
* ████ 注意 ████
|
||||
*
|
||||
* 教材中的线性链表命名为LinkList,
|
||||
* 这里为了与单链表区分,故将其命名为ELinkList。
|
||||
* 线性链表可以理解成对普通链表的一种扩展。
|
||||
*/
|
||||
|
||||
/* 线性链表元素类型定义 */
|
||||
typedef int ElemType;
|
||||
|
||||
/*
|
||||
* 线性链表结构
|
||||
*
|
||||
* 注:这里的线性链表存在头结点
|
||||
*/
|
||||
typedef struct LNode {
|
||||
ElemType data;
|
||||
struct LNode* next;
|
||||
} LNode, * Link, * Position;
|
||||
|
||||
/* 维护线性链表头尾指针及长度信息 */
|
||||
typedef struct {
|
||||
Link head, tail; // 分别指向线性链表中的头结点和尾结点
|
||||
int len; // 指示线性链表中数据元素的个数
|
||||
} ELinkList;
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 内存操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 内存分配
|
||||
*
|
||||
* 为线性链表申请一个结点,并存入指定的数据e。
|
||||
*
|
||||
*【备注】
|
||||
* static修饰的含义是该函数仅限当前文件内使用
|
||||
*/
|
||||
Status MakeNode(Link* p, ElemType e);
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表常规操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(ELinkList* L);
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表扩展操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 向尾部添加
|
||||
*
|
||||
* 将s所指的一串结点链接在链表L后面
|
||||
*/
|
||||
Status Append(ELinkList* L, Link s);
|
||||
|
||||
#endif
|
||||
95
Dev-C++/CourseBook/0405_WordList/HString.cpp
Normal file
95
Dev-C++/CourseBook/0405_WordList/HString.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*=========================
|
||||
* 串的堆分配存储表示(堆串)
|
||||
*
|
||||
* 包含算法: 4.4
|
||||
==========================*/
|
||||
|
||||
#include "HString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(HString* T, const char* chars) {
|
||||
int i, j;
|
||||
|
||||
// 求chars的长度
|
||||
i = (int) strlen(chars);
|
||||
|
||||
// 没有有效元素
|
||||
if(i == 0) {
|
||||
(*T).ch = NULL;
|
||||
(*T).length = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 存在有效元素时,需要分配存储空间
|
||||
(*T).ch = (char*) malloc(i * sizeof(char));
|
||||
if(!((*T).ch)) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
for(j = 0; j < i; j++) {
|
||||
(*T).ch[j] = chars[j];
|
||||
}
|
||||
|
||||
(*T).length = i;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 比较
|
||||
*
|
||||
* 比较串S和串T,返回比较结果。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrCompare(HString S, HString T) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < S.length && i < T.length; i++) {
|
||||
// 遇到不同的字符时,比较其大小
|
||||
if(S.ch[i] != T.ch[i]) {
|
||||
return S.ch[i] - T.ch[i];
|
||||
}
|
||||
}
|
||||
|
||||
return S.length - T.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* 复制
|
||||
*
|
||||
* 将串S复制到串T。
|
||||
*/
|
||||
Status StrCopy(HString* T, HString S) {
|
||||
int i;
|
||||
|
||||
if(S.length == 0) {
|
||||
(*T).ch = NULL;
|
||||
(*T).length = 0;
|
||||
} else {
|
||||
// 分配空间
|
||||
(*T).ch = (char*) malloc(S.length * sizeof(char));
|
||||
if(!(*T).ch) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
// 复制元素
|
||||
for(i = 0; i < S.length; i++) {
|
||||
(*T).ch[i] = S.ch[i];
|
||||
}
|
||||
|
||||
// 复制长度信息
|
||||
(*T).length = S.length;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
53
Dev-C++/CourseBook/0405_WordList/HString.h
Normal file
53
Dev-C++/CourseBook/0405_WordList/HString.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*=========================
|
||||
* 串的堆分配存储表示(堆串)
|
||||
*
|
||||
* 包含算法: 4.4
|
||||
==========================*/
|
||||
|
||||
#ifndef HSTRING
|
||||
#define HSTRING
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include <string.h> // 提供strlen原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/*
|
||||
* 串的堆存储表示
|
||||
*
|
||||
* 注:有效元素从ch的0号单元开始存储
|
||||
*/
|
||||
typedef struct {
|
||||
char* ch; // 若是非空串,则按串长分配存储区,否则ch为NULL
|
||||
int length;
|
||||
} HString;
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(HString* T, const char* chars);
|
||||
|
||||
/*
|
||||
* 比较
|
||||
*
|
||||
* 比较串S和串T,返回比较结果。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrCompare(HString S, HString T);
|
||||
|
||||
/*
|
||||
* 复制
|
||||
*
|
||||
* 将串S复制到串T。
|
||||
*/
|
||||
Status StrCopy(HString* T, HString S);
|
||||
|
||||
#endif
|
||||
7
Dev-C++/CourseBook/0405_WordList/TestData.txt
Normal file
7
Dev-C++/CourseBook/0405_WordList/TestData.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Êé ºÅ Êé Ãû
|
||||
005 Computer Data Structures
|
||||
010 Introduction to Data Structures
|
||||
023 Fundamentals of Data Structures
|
||||
034 The Design and Analysis of Computer Algorithms
|
||||
050 Introduction to Numerical Analysis
|
||||
067 Numerical Analysis
|
||||
27
Dev-C++/CourseBook/0405_WordList/WordList-main.cpp
Normal file
27
Dev-C++/CourseBook/0405_WordList/WordList-main.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <stdio.h> // 提供system原型
|
||||
#include "WordList.h" //**▲04 串**//
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
FILE* fp;
|
||||
char line[MaxLineLen];
|
||||
|
||||
char* bookinfo = "TestData.txt"; // 书目文件名
|
||||
char* bookidx = "BookIdx.txt"; // 关键词索引文件名
|
||||
|
||||
// 创建索引表
|
||||
Main(bookinfo, bookidx);
|
||||
|
||||
// 显示索引表到屏幕
|
||||
if((fp = fopen(bookidx, "r"))!=NULL) {
|
||||
printf("---------索引表生成功!---------\n\n");
|
||||
|
||||
while(feof(fp)==FALSE) {
|
||||
fgets(line, MaxLineLen, fp);
|
||||
printf("%s", line);
|
||||
}
|
||||
} else {
|
||||
printf("---------未发现索引表!---------\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
308
Dev-C++/CourseBook/0405_WordList/WordList.cpp
Normal file
308
Dev-C++/CourseBook/0405_WordList/WordList.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/*===========================================
|
||||
* 索引表
|
||||
*
|
||||
* 包含算法: 4.9、4.10、4.11、4.12、4.13、4.14
|
||||
============================================*/
|
||||
|
||||
#include "WordList.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.9 ████████
|
||||
*
|
||||
* 从文件bookinfo中读取书目信息,并依此创建相应的关键词索引表,然后将索引表写入文件bookidx。
|
||||
*/
|
||||
void Main(char* bookinfo, char* bookidx) {
|
||||
FILE* f, * g;
|
||||
char head[MaxLineLen]; // 书目的表头信息(未使用)
|
||||
IdxListType idxlist; // 关键词索引表
|
||||
ElemType bno; // 书号
|
||||
int count;
|
||||
|
||||
// 以“只读”模式打开书目文件
|
||||
if((f = fopen(bookinfo, "r")) != NULL) {
|
||||
|
||||
// 以“只写”模式打开索引文件
|
||||
if((g = fopen(bookidx, "w")) != NULL) {
|
||||
|
||||
// 初始化索引表
|
||||
InitIdxList(&idxlist);
|
||||
|
||||
// 跳过文件第一行
|
||||
fgets(head, MaxLineLen, f);
|
||||
|
||||
count = 0;
|
||||
|
||||
// 如果未到文件结尾,则一直读文件
|
||||
while(feof(f) == FALSE && count < MaxBookNum) {
|
||||
|
||||
// 从文件f读入一个书目信息到书目缓冲区gBuf
|
||||
GetLine(f);
|
||||
|
||||
// 从gBuf提取关键词到词表gWdList,书号存入bno
|
||||
ExtractKeyWord(&bno);
|
||||
|
||||
// 将书号及对应的关键词插入索引表idxlist
|
||||
InsIdxList(&idxlist, bno);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
// 向文件g中写入索引表数据
|
||||
PutText(g, idxlist);
|
||||
|
||||
fclose(g);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 初始化索引表
|
||||
*
|
||||
*【注】
|
||||
* 教材中将索引表表头置为空串,但这里设定了一个有意义的表头
|
||||
*/
|
||||
void InitIdxList(IdxListType* idxlist) {
|
||||
// 索引表的表头信息
|
||||
char* chars = "关键词 书号索引";
|
||||
IdxTermType e;
|
||||
|
||||
// 初始化表头信息
|
||||
StrAssign(&(e.key), chars);
|
||||
|
||||
// 初始化书号索引链表
|
||||
InitList(&(e.bnolist));
|
||||
|
||||
(*idxlist).item[0] = e;
|
||||
|
||||
// 表头为第0条信息
|
||||
(*idxlist).last = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 从文件f中读取一条书目信息存入书目缓冲区gBuf。
|
||||
*/
|
||||
void GetLine(FILE* f) {
|
||||
// 读取一行数据,存入缓冲区gBuf
|
||||
fgets(gBuf, MaxLineLen, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* 从缓冲区gBuf中提取书名关键词到词表gWdList,书号存入bno。
|
||||
*/
|
||||
void ExtractKeyWord(ElemType* bno) {
|
||||
char delim[] = {'-', ' ', '\r', '\n', '\t'}; // 分隔符
|
||||
char* title; // 书名
|
||||
char* token; // 从书名中分解出的关键词
|
||||
|
||||
// 分解书目字符串,将书号存入bno(十进制),并用title指向剩下的字符串(书名)
|
||||
*bno = (int) strtol(gBuf, &title, 10);
|
||||
|
||||
// 将书名的由大写变小写
|
||||
strlwr(title);
|
||||
|
||||
// 清空关键词词表
|
||||
gWdList.last = 0;
|
||||
|
||||
// 分解关键词
|
||||
for(token = strtok(title, delim); token != NULL; token = strtok(NULL, delim)) {
|
||||
// 如果该关键词是常用词,则忽略它
|
||||
if(isCommonWords(token) == TRUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 记下从书名中提取的关键词
|
||||
gWdList.item[gWdList.last++] = token;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.10 ████████
|
||||
*
|
||||
* 将书号bno对应的书名中的关键词按词典顺序插入到索引表idxlist。
|
||||
*/
|
||||
Status InsIdxList(IdxListType* idxlist, int bno) {
|
||||
int i, j;
|
||||
Boolean boo;
|
||||
HString wd;
|
||||
|
||||
if(gWdList.last <= 0) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 遍历书号bno对应的书名中的所有关键词
|
||||
for(i = 0; i < gWdList.last; i++) {
|
||||
// 获取待插入的关键词
|
||||
GetWord(i, &wd);
|
||||
|
||||
// 判断该关键词是否已经位于索引表中
|
||||
j = Locate(*idxlist, wd, &boo);
|
||||
|
||||
// 如果该关键词不在索引表中,则需要插入关键词
|
||||
if(boo == FALSE) {
|
||||
// 将关键词wd插入到索引表
|
||||
InsertNewKey(idxlist, j, wd);
|
||||
}
|
||||
|
||||
// 在关键词已存在的情形下,插入书号
|
||||
if(!InsertBook(idxlist, j, bno)) {
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.11 ████████
|
||||
*
|
||||
* 用wd返回词表gWdList中第i个关键词。
|
||||
*/
|
||||
void GetWord(int i, HString* wd) {
|
||||
if(i < 0 || i > gWdList.last - 1) {
|
||||
StrAssign(wd, "");
|
||||
} else {
|
||||
StrAssign(wd, gWdList.item[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.12 ████████
|
||||
*
|
||||
* 查询在索引表idxlist中是否存在与wd相等的关键词。
|
||||
* 若存在,则返回wd在词表中的位置,并置b为TRUE。
|
||||
* 若不存在,则返回wd应插入的位置,并置b为FALSE。
|
||||
*/
|
||||
int Locate(IdxListType idxlist, HString wd, Boolean* b) {
|
||||
int i, m = -1;
|
||||
|
||||
/*
|
||||
* 在索引表idxlist中查找关键词wd是否存在
|
||||
* 注:0号单元存储了表头信息
|
||||
*/
|
||||
for(i = idxlist.last; i > 0 && (m = StrCompare(idxlist.item[i].key, wd)) > 0; i--) {
|
||||
}
|
||||
|
||||
// 如果找到了关键词wd
|
||||
if(m == 0) {
|
||||
*b = TRUE;
|
||||
return i;
|
||||
} else {
|
||||
*b = FALSE;
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.13 ████████
|
||||
*
|
||||
* 在索引表的索引i(>=0)处插入关键词wd,并初始化书号索引的链表为空表。
|
||||
*/
|
||||
void InsertNewKey(IdxListType* idxlist, int i, HString wd) {
|
||||
int j;
|
||||
|
||||
/*
|
||||
* 索引项后移
|
||||
* 注:0号单元存储了表头信息
|
||||
*/
|
||||
for(j = (*idxlist).last; j >= i; j--) {
|
||||
(*idxlist).item[j + 1] = (*idxlist).item[j];
|
||||
}
|
||||
|
||||
// 插入索引项
|
||||
StrCopy(&((*idxlist).item[i].key), wd);
|
||||
|
||||
// 初始化书号索引链表
|
||||
InitList(&((*idxlist).item[i].bnolist));
|
||||
|
||||
// 索引数目增一
|
||||
(*idxlist).last++;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.14 ████████
|
||||
*
|
||||
* 为索引表在索引i(>0)处的关键词插入书号。
|
||||
*/
|
||||
Status InsertBook(IdxListType* idxlist, int i, ElemType bno) {
|
||||
Link p;
|
||||
|
||||
// 内存分配失败
|
||||
if(MakeNode(&p, bno) == FALSE) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 插入新的书号索引
|
||||
Append(&((*idxlist).item[i].bnolist), p);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 将生成的索引表idxlist输出到文件g。
|
||||
*/
|
||||
void PutText(FILE* g, IdxListType idxlist) {
|
||||
int i, j, m, n;
|
||||
Link p;
|
||||
HString S;
|
||||
ELinkList L;
|
||||
|
||||
if(idxlist.last <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先输出表头信息
|
||||
S = idxlist.item[0].key;
|
||||
for(m = 0; m < S.length; m++) {
|
||||
fprintf(g, "%c", S.ch[m]);
|
||||
}
|
||||
fprintf(g, "\n");
|
||||
|
||||
// 输出索引信息
|
||||
for(i = 1; i <= idxlist.last; i++) {
|
||||
// 1.输出关键词
|
||||
S = idxlist.item[i].key;
|
||||
for(m = 0; m < S.length; m++) {
|
||||
fprintf(g, "%c", S.ch[m]);
|
||||
}
|
||||
|
||||
// 2.输出空格
|
||||
for(j = 1; j <= 18 - idxlist.item[i].key.length; j++) {
|
||||
fprintf(g, " ");
|
||||
}
|
||||
|
||||
// 3.输出书号索引
|
||||
L = idxlist.item[i].bnolist;
|
||||
for(n = 1, p = L.head->next; n <= L.len; n++) {
|
||||
fprintf(g, "%03d", p->data);
|
||||
p = p->next;
|
||||
if(p) {
|
||||
fprintf(g, ",");
|
||||
}
|
||||
}
|
||||
|
||||
// 4.输出换行
|
||||
fprintf(g, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 判断str是否为常用词
|
||||
static Status isCommonWords(char* str) {
|
||||
int i;
|
||||
|
||||
// 常用词词表,这些词汇会被排除在关键词之外
|
||||
WordListType words = {{"a", "an", "the", "of", "and", "is", "to", "as", "in", "for"}, 10};
|
||||
|
||||
// 查询常用词词表
|
||||
for(i = 0; i < words.last; i++) {
|
||||
// 对两字符串进行忽略大小写的比较
|
||||
if(strcmpi(str, words.item[i]) == 0) {
|
||||
// 如果该字符串是常用词,则返回TRUE
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
131
Dev-C++/CourseBook/0405_WordList/WordList.dev
Normal file
131
Dev-C++/CourseBook/0405_WordList/WordList.dev
Normal file
@@ -0,0 +1,131 @@
|
||||
[Project]
|
||||
FileName=WordList.dev
|
||||
Name=WordList
|
||||
Type=1
|
||||
Ver=2
|
||||
ObjFiles=
|
||||
Includes=
|
||||
Libs=
|
||||
PrivateResource=
|
||||
ResourceIncludes=
|
||||
MakeIncludes=
|
||||
Compiler=
|
||||
CppCompiler=
|
||||
Linker=
|
||||
IsCpp=0
|
||||
Icon=
|
||||
ExeOutput=
|
||||
ObjectOutput=
|
||||
LogOutput=
|
||||
LogOutputEnabled=0
|
||||
OverrideOutput=0
|
||||
OverrideOutputName=
|
||||
HostApplication=
|
||||
UseCustomMakefile=0
|
||||
CustomMakefile=
|
||||
CommandLine=
|
||||
Folders=
|
||||
IncludeVersionInfo=0
|
||||
SupportXPThemes=0
|
||||
CompilerSet=1
|
||||
CompilerSettings=0000000000000000001000000
|
||||
UnitCount=8
|
||||
|
||||
[VersionInfo]
|
||||
Major=1
|
||||
Minor=0
|
||||
Release=0
|
||||
Build=0
|
||||
LanguageID=1033
|
||||
CharsetID=1252
|
||||
CompanyName=
|
||||
FileVersion=
|
||||
FileDescription=Developed using the Dev-C++ IDE
|
||||
InternalName=
|
||||
LegalCopyright=
|
||||
LegalTrademarks=
|
||||
OriginalFilename=
|
||||
ProductName=
|
||||
ProductVersion=
|
||||
AutoIncBuildNr=0
|
||||
SyncProduct=1
|
||||
|
||||
[Unit7]
|
||||
FileName=WordList-main.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit1]
|
||||
FileName=ELinkList.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit3]
|
||||
FileName=HString.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit5]
|
||||
FileName=WordList.cpp
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit2]
|
||||
FileName=ELinkList.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit4]
|
||||
FileName=HString.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit6]
|
||||
FileName=WordList.h
|
||||
CompileCpp=0
|
||||
Folder=
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit8]
|
||||
FileName=TestData.txt
|
||||
Folder=
|
||||
Compile=0
|
||||
Link=0
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
130
Dev-C++/CourseBook/0405_WordList/WordList.h
Normal file
130
Dev-C++/CourseBook/0405_WordList/WordList.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*===========================================
|
||||
* 索引表
|
||||
*
|
||||
* 包含算法: 4.9、4.10、4.11、4.12、4.13、4.14
|
||||
============================================*/
|
||||
|
||||
#ifndef WORDLIST_H
|
||||
#define WORDLIST_H
|
||||
|
||||
#include <stdio.h> // 提供fopen、fclose、feof、fgets原型
|
||||
#include <stdlib.h> // 提供exit、strtol原型
|
||||
#include <string.h> // 提供strlen、strcmpi、strlwr原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
#include "ELinkList.h" //**▲02 线性表**//
|
||||
#include "HString.h" //**▲04 串**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define MaxBookNum 1000 // 允许的最大书目数(假设最多只对1000本书建索引表)
|
||||
#define MaxKeyNum 2500 // 索引表最大容量(索引项数量的最大值)
|
||||
#define MaxLineLen 500 // 书目串(行)的最大长度
|
||||
#define MaxWordNum 100 // 词表的最大容量
|
||||
|
||||
/* 类型定义 */
|
||||
|
||||
// 布尔类型
|
||||
typedef Status Boolean;
|
||||
|
||||
// 词表类型(顺序表)
|
||||
typedef struct {
|
||||
char* item[MaxWordNum]; // 词表集合
|
||||
int last; // 词表的长度
|
||||
} WordListType;
|
||||
|
||||
// 索引项类型(索引表的行)
|
||||
typedef struct {
|
||||
HString key; // 关键词
|
||||
ELinkList bnolist; // 存放书号索引的链表
|
||||
} IdxTermType;
|
||||
|
||||
/*
|
||||
* 索引表类型
|
||||
*
|
||||
*【注】
|
||||
* 0号单元存储表头信息,这一点与教材有所不同
|
||||
*/
|
||||
typedef struct {
|
||||
IdxTermType item[MaxKeyNum + 1]; // 索引项的集合
|
||||
int last; // 索引表中包含的索引项数目
|
||||
} IdxListType;
|
||||
|
||||
/* 全局变量(变量名称前面都加了g标记) */
|
||||
|
||||
// 书目缓存区
|
||||
static char gBuf[MaxLineLen];
|
||||
|
||||
// 关键词词表(普通词表),已经排除了常用词
|
||||
static WordListType gWdList;
|
||||
|
||||
|
||||
/*
|
||||
* ████████ 算法4.9 ████████
|
||||
*
|
||||
* 从文件bookinfo中读取书目信息,并依此创建相应的关键词索引表,然后将索引表写入文件bookidx。
|
||||
*/
|
||||
void Main(char* bookinfo, char* bookidx);
|
||||
|
||||
/*
|
||||
* 初始化索引表
|
||||
*
|
||||
*【注】
|
||||
* 教材中将索引表表头置为空串,但这里设定了一个有意义的表头
|
||||
*/
|
||||
void InitIdxList(IdxListType* idxlist);
|
||||
|
||||
/*
|
||||
* 从文件f中读取一条书目信息存入书目缓冲区gBuf。
|
||||
*/
|
||||
void GetLine(FILE* f);
|
||||
|
||||
/*
|
||||
* 从缓冲区gBuf中提取书名关键词到词表gWdList,书号存入bno。
|
||||
*/
|
||||
void ExtractKeyWord(ElemType* bno);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.10 ████████
|
||||
*
|
||||
* 将书号bno对应的书名关键词按词典顺序插入到索引表idxlist。
|
||||
*/
|
||||
Status InsIdxList(IdxListType* idxlist, int bno);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.11 ████████
|
||||
*
|
||||
* 用wd返回词表gWdList中第i个关键词。
|
||||
*/
|
||||
void GetWord(int i, HString* wd);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.12 ████████
|
||||
*
|
||||
* 查询在索引表idxlist中是否存在与wd相等的关键词。
|
||||
* 若存在,则返回wd在词表中的位置,并置b为TRUE。
|
||||
* 若不存在,则返回wd应插入的位置,并置b为FALSE。
|
||||
*/
|
||||
int Locate(IdxListType idxlist, HString wd, Boolean* b);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.13 ████████
|
||||
*
|
||||
* 在索引表的索引i(>=0)处插入关键词wd,并初始化书号索引的链表为空表。
|
||||
*/
|
||||
void InsertNewKey(IdxListType* idxlist, int i, HString wd);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.14 ████████
|
||||
*
|
||||
* 为索引表在索引i(>0)处的关键词插入书号。
|
||||
*/
|
||||
Status InsertBook(IdxListType* idxlist, int i, int bno);
|
||||
|
||||
/*
|
||||
* 将生成的索引表idxlist输出到文件g。
|
||||
*/
|
||||
void PutText(FILE* g, IdxListType idxlist);
|
||||
|
||||
// 判断str是否为常用词
|
||||
static Status isCommonWords(char* str);
|
||||
|
||||
#endif
|
||||
54
README.md
54
README.md
@@ -91,29 +91,31 @@ Commit信息中的`emoji`参考来源:
|
||||
|
||||
## 附:教材源码目录
|
||||
|
||||
| 章 | 节 | 内容 | 包含算法 | 备注 |
|
||||
| :--------- | :---------- | :----------- | :-------------------- | :------------------- |
|
||||
| 01 绪论 | Status | | | 定义一些共享常量和函数 |
|
||||
| 02 线性表 | SqList | 顺序表 | 2.3、2.4、2.5、2.6 | 线性表的顺序存储结构 |
|
||||
| | Union | A=A∪B | 2.1 | |
|
||||
| | MergeSqList | C=A+B | 2.2、2.7 | 归并顺序表 |
|
||||
| | LinkList | 链表 | 2.8、2.9、2.10、2.11 | 线性表的链式存储结构 |
|
||||
| | MergeList | C=A+B | 2.12 | 归并链表 |
|
||||
| | SLinkList | 静态链表 | 2.13、2.14、2.15、2.16 | |
|
||||
| | Difference | (A-B)∪(B-A) | 2.17 | |
|
||||
| | DuLinkList | 双向循环链表 | 2.18、2.19 | |
|
||||
| | ELinkList | 扩展的线性链表 | 2.20 | |
|
||||
| | MergeEList | C=A+B | 2.21 | 归并扩展的线性链表 |
|
||||
| | Polynomial | 一元多项式 | 2.22、2.23 | |
|
||||
| 03 栈和队列 | SqStack | 栈 | | 顺序存储结构 |
|
||||
| | Conversion | 进制转换 | 3.1 | 栈的应用 |
|
||||
| | LineEdit | 行编辑程序 | 3.2 | 栈的应用 |
|
||||
| | Maze | 迷宫寻路 | 3.3 | 栈的应用 |
|
||||
| | Expression | 表达式求值 | 3.4 | 栈的应用 |
|
||||
| | Hanoi | 汉诺塔 | 3.5 | 递归 |
|
||||
| | LinkQueue | 链列 | | 链式存储结构 |
|
||||
| | SqQueue | 顺序队列 | | 循环队列,顺序存储结构 |
|
||||
| | BankQueuing | 模拟银行排队 | 3.6、3.7 | 队列的应用 |
|
||||
| 04 串 | SString | 顺序串 | 4.1、4.2、4.3、4.5 | 顺序存储 |
|
||||
| | HString | 堆串 | 4.4 | 顺序存储,动态分配内存 |
|
||||
| | LString | 块链串 | | 顺序存储+链式存储 |
|
||||
| 章 | 节 | 内容 | 包含算法 | 备注 |
|
||||
| :--------- | :---------- | :----------- | :------------------------------- | :------------------- |
|
||||
| 01 绪论 | Status | | | 定义一些共享常量和函数 |
|
||||
| 02 线性表 | SqList | 顺序表 | 2.3、2.4、2.5、2.6 | 线性表的顺序存储结构 |
|
||||
| | Union | A=A∪B | 2.1 | |
|
||||
| | MergeSqList | C=A+B | 2.2、2.7 | 归并顺序表 |
|
||||
| | LinkList | 链表 | 2.8、2.9、2.10、2.11 | 线性表的链式存储结构 |
|
||||
| | MergeList | C=A+B | 2.12 | 归并链表 |
|
||||
| | SLinkList | 静态链表 | 2.13、2.14、2.15、2.16 | |
|
||||
| | Difference | (A-B)∪(B-A) | 2.17 | |
|
||||
| | DuLinkList | 双向循环链表 | 2.18、2.19 | |
|
||||
| | ELinkList | 扩展的线性链表 | 2.20 | |
|
||||
| | MergeEList | C=A+B | 2.21 | 归并扩展的线性链表 |
|
||||
| | Polynomial | 一元多项式 | 2.22、2.23 | |
|
||||
| 03 栈和队列 | SqStack | 栈 | | 顺序存储结构 |
|
||||
| | Conversion | 进制转换 | 3.1 | 栈的应用 |
|
||||
| | LineEdit | 行编辑程序 | 3.2 | 栈的应用 |
|
||||
| | Maze | 迷宫寻路 | 3.3 | 栈的应用 |
|
||||
| | Expression | 表达式求值 | 3.4 | 栈的应用 |
|
||||
| | Hanoi | 汉诺塔 | 3.5 | 递归 |
|
||||
| | LinkQueue | 链列 | | 链式存储结构 |
|
||||
| | SqQueue | 顺序队列 | | 循环队列,顺序存储结构 |
|
||||
| | BankQueuing | 模拟银行排队 | 3.6、3.7 | 队列的应用 |
|
||||
| 04 串 | SString | 顺序串 | 4.1、4.2、4.3、4.5 | 顺序存储 |
|
||||
| | HString | 堆串 | 4.4 | 顺序存储,动态分配内存 |
|
||||
| | LString | 块链串 | | 顺序存储+链式存储 |
|
||||
| | KMP | KMP算法 | 4.6、4.7、4.8 | 字符串匹配算法 |
|
||||
| | WordList | 关键词索引 | 4.9、4.10、4.11、4.12、4.13、4.14 | 堆串和线性表的应用 |
|
||||
|
||||
78
VisualC++/CourseBook/0404_KMP/0404_KMP.vcxproj
Normal file
78
VisualC++/CourseBook/0404_KMP/0404_KMP.vcxproj
Normal file
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5D2A1F0B-F177-43A9-873A-56C7E08E6987}</ProjectGuid>
|
||||
<RootNamespace>My0404_KMP</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(SolutionDir)\..\Status;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>$(SolutionDir)\..\Status\Status.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="KMP.h" />
|
||||
<ClInclude Include="SString.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="KMP-main.c" />
|
||||
<ClCompile Include="KMP.c" />
|
||||
<ClCompile Include="SString.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
36
VisualC++/CourseBook/0404_KMP/0404_KMP.vcxproj.filters
Normal file
36
VisualC++/CourseBook/0404_KMP/0404_KMP.vcxproj.filters
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="KMP.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SString.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="KMP.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KMP-main.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SString.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
3
VisualC++/CourseBook/0404_KMP/0404_KMP.vcxproj.user
Normal file
3
VisualC++/CourseBook/0404_KMP/0404_KMP.vcxproj.user
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
64
VisualC++/CourseBook/0404_KMP/KMP-main.c
Normal file
64
VisualC++/CourseBook/0404_KMP/KMP-main.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "KMP.h" //**▲04 串**//
|
||||
|
||||
// 测试函数,打印字符串
|
||||
void PrintElem(SString S);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char* s = "abaaabcaabaabcacabaabcaabaabcac";
|
||||
char* t = "abaabcac";
|
||||
SString S, T;
|
||||
int* next; // 模式串的next函数值
|
||||
int* nextval; // 模式串的nextval函数值
|
||||
int pos; // 匹配起点
|
||||
int i, j;
|
||||
|
||||
StrAssign(S, s); // 初始化主串
|
||||
printf("S = ");
|
||||
PrintElem(S);
|
||||
|
||||
StrAssign(T, t); // 初始化模式串
|
||||
printf("T = ");
|
||||
PrintElem(T);
|
||||
|
||||
|
||||
// 注:next数组和nextval数组的0号单元是弃用的,从1号单元开始存储有效数据
|
||||
next = (int*) malloc((T[0] + 1) * sizeof(int));
|
||||
nextval = (int*) malloc((T[0] + 1) * sizeof(int));
|
||||
|
||||
get_next(T, next); // 算法4.7
|
||||
get_nextval(T, nextval); // 算法4.8,即算法4.7的改进版
|
||||
|
||||
printf("next : ");
|
||||
for(i = 1; i <= T[0]; i++) {
|
||||
printf("%d", next[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("nextval : ");
|
||||
for(i = 1; i <= T[0]; i++) {
|
||||
printf("%d", nextval[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
|
||||
pos = 1;
|
||||
|
||||
i = Index_KMP(S, T, pos, next);
|
||||
j = Index_KMP(S, T, pos, nextval);
|
||||
|
||||
printf("从%d个字符起,T 在 S 中第一次匹配成功的位置为 %d\n", pos, i);
|
||||
printf("从%d个字符起,T 在 S 中第一次匹配成功的位置为 %d\n", pos, j);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 测试函数,打印字符串
|
||||
void PrintElem(SString S) {
|
||||
int i;
|
||||
|
||||
for(i = 1; i <= S[0]; i++) {
|
||||
printf("%c", S[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
106
VisualC++/CourseBook/0404_KMP/KMP.c
Normal file
106
VisualC++/CourseBook/0404_KMP/KMP.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*=======================
|
||||
* KMP算法
|
||||
*
|
||||
* 包含算法: 4.6、4.7、4.8
|
||||
========================*/
|
||||
|
||||
#include "KMP.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.6 ████████
|
||||
*
|
||||
* 查找
|
||||
*
|
||||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||||
* 如果查找成功,返回匹配的位置。
|
||||
*
|
||||
*【注】
|
||||
* 1.该实现用到了KMP算法,是一种比较高效的字符串匹配方式
|
||||
* 2.教材中没有next参数
|
||||
*/
|
||||
int Index_KMP(SString S, SString T, int pos, int next[]) {
|
||||
int i = pos;
|
||||
int j = 1;
|
||||
|
||||
if(pos < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 比较字符串
|
||||
while(i <= S[0] && j <= T[0]) {
|
||||
/*
|
||||
* 两种情形:
|
||||
* 1.在模式串的第一个字符处就失配
|
||||
* 2.主串和模式串处的字符相等
|
||||
*/
|
||||
if(j == 0 || S[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
} else {
|
||||
// 失配时回到前一个适当的位置
|
||||
j = next[j];
|
||||
}
|
||||
}
|
||||
|
||||
if(j > T[0]) {
|
||||
// 匹配成功,返回匹配位置
|
||||
return i - T[0];
|
||||
} else {
|
||||
// 匹配失败
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.7 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
*/
|
||||
void get_next(SString T, int next[]) {
|
||||
int i = 1;
|
||||
int j = 0;
|
||||
|
||||
// 模式串第一个字符处失配时,模式串需要从头比较,主串需要前进到下一个位置比较
|
||||
next[1] = 0;
|
||||
|
||||
// 遍历模式串上的字符
|
||||
while(i < T[0]) {
|
||||
if(j == 0 || T[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
next[i] = j;
|
||||
} else {
|
||||
j = next[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.8 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
* 这是一个优化后的版本,效率较算法4.7有所提高。
|
||||
*/
|
||||
void get_nextval(SString T, int nextval[]) {
|
||||
int i = 1;
|
||||
int j = 0;
|
||||
|
||||
// 模式串第一个字符处失配时,模式串需要从头比较,主串需要前进到下一个位置比较
|
||||
nextval[1] = 0;
|
||||
|
||||
// 遍历模式串上的字符
|
||||
while(i < T[0]) {
|
||||
if(j==0 || T[i] == T[j]) {
|
||||
i++;
|
||||
j++;
|
||||
|
||||
if(T[i] != T[j]) {
|
||||
nextval[i] = j;
|
||||
} else {
|
||||
nextval[i] = nextval[j];
|
||||
}
|
||||
} else {
|
||||
j = nextval[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
43
VisualC++/CourseBook/0404_KMP/KMP.h
Normal file
43
VisualC++/CourseBook/0404_KMP/KMP.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*=======================
|
||||
* KMP算法
|
||||
*
|
||||
* 包含算法: 4.6、4.7、4.8
|
||||
========================*/
|
||||
|
||||
#ifndef KMP_H
|
||||
#define KMP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "SString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.6 ████████
|
||||
*
|
||||
* 查找
|
||||
*
|
||||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||||
* 如果查找成功,返回匹配的位置。
|
||||
*
|
||||
*【注】
|
||||
* 1.该实现用到了KMP算法,是一种比较高效的字符串匹配方式
|
||||
* 2.教材中没有next参数
|
||||
*/
|
||||
int Index_KMP(SString S, SString T, int pos, int next[]);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.7 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
*/
|
||||
void get_next(SString T, int next[]);
|
||||
|
||||
/*
|
||||
* ████████ 算法4.8 ████████
|
||||
*
|
||||
* 计算模式串的“失配数组”,用于KMP算法。
|
||||
* 这是一个优化后的版本,效率较算法4.7有所提高。
|
||||
*/
|
||||
void get_nextval(SString T, int nextval[]);
|
||||
|
||||
#endif
|
||||
33
VisualC++/CourseBook/0404_KMP/SString.c
Normal file
33
VisualC++/CourseBook/0404_KMP/SString.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*=============================
|
||||
* 串的定长顺序存储表示(顺序串)
|
||||
*
|
||||
* 包含算法: 4.1、4.2、4.3、4.5
|
||||
==============================*/
|
||||
|
||||
#include "SString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(SString T, const char* chars) {
|
||||
int i, len;
|
||||
|
||||
len = (int) strlen(chars);
|
||||
|
||||
// chars过长
|
||||
if(len > MAXSTRLEN) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
T[0] = len;
|
||||
for(i = 1; i <= len; i++) {
|
||||
T[i] = chars[i - 1];
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
36
VisualC++/CourseBook/0404_KMP/SString.h
Normal file
36
VisualC++/CourseBook/0404_KMP/SString.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*=============================
|
||||
* 串的定长顺序存储表示(顺序串)
|
||||
*
|
||||
* 包含算法: 4.1、4.2、4.3、4.5
|
||||
==============================*/
|
||||
|
||||
#ifndef SSTRING_H
|
||||
#define SSTRING_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h> // 提供strlen原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/* 宏定义 */
|
||||
#define MAXSTRLEN 255 // 顺序串的最大串长
|
||||
|
||||
/*
|
||||
* 串的顺序存储类型定义
|
||||
*
|
||||
* 注:有效元素从SString的1号单元开始存储
|
||||
* SString的0号单元用来存储其长度
|
||||
*/
|
||||
typedef unsigned char SString[MAXSTRLEN + 1]; // 0号单元存放串的长度
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(SString T, const char* chars);
|
||||
|
||||
#endif
|
||||
83
VisualC++/CourseBook/0405_WordList/0405_WordList.vcxproj
Normal file
83
VisualC++/CourseBook/0405_WordList/0405_WordList.vcxproj
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{FA2740D7-2D96-4F57-AE79-FCDA5C13CA86}</ProjectGuid>
|
||||
<RootNamespace>My0405_WordList</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(SolutionDir)\..\Status;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>$(SolutionDir)\..\Status\Status.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ELinkList.c" />
|
||||
<ClCompile Include="HString.c" />
|
||||
<ClCompile Include="WordList-main.c" />
|
||||
<ClCompile Include="WordList.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELinkList.h" />
|
||||
<ClInclude Include="HString.h" />
|
||||
<ClInclude Include="WordList.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TestData.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ELinkList.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HString.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WordList.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WordList-main.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELinkList.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HString.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WordList.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TestData.txt">
|
||||
<Filter>资源文件</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
||||
95
VisualC++/CourseBook/0405_WordList/ELinkList.c
Normal file
95
VisualC++/CourseBook/0405_WordList/ELinkList.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*=======================
|
||||
* 扩展的单链表(线性链表)
|
||||
*
|
||||
* 包含算法: 2.20
|
||||
========================*/
|
||||
|
||||
#include "ELinkList.h" //**▲02 线性表**//
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 内存操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 内存分配
|
||||
*
|
||||
* 为线性链表申请一个结点,并存入指定的数据e。
|
||||
*
|
||||
*【备注】
|
||||
* static修饰的含义是该函数仅限当前文件内使用
|
||||
*/
|
||||
Status MakeNode(Link* p, ElemType e) {
|
||||
if(p == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 申请空间
|
||||
*p = (Link) malloc(sizeof(LNode));
|
||||
if(*p == NULL) {
|
||||
// 这里没有退出程序,而是返回错误提示
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
(*p)->data = e;
|
||||
(*p)->next = NULL;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表常规操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(ELinkList* L) {
|
||||
Link p;
|
||||
|
||||
if(L == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 创建头结点
|
||||
p = (Link) malloc(sizeof(LNode));
|
||||
if(p == NULL) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
p->next = NULL;
|
||||
|
||||
// 只有头结点时,首位游标指向自身
|
||||
(*L).head = (*L).tail = p;
|
||||
(*L).len = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表扩展操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 向尾部添加
|
||||
*
|
||||
* 将s所指的一串结点链接在链表L后面
|
||||
*/
|
||||
Status Append(ELinkList* L, Link s) {
|
||||
int count;
|
||||
|
||||
if(L == NULL || (*L).head == NULL || s == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
(*L).tail->next = s;
|
||||
|
||||
// 确定新的尾结点位置
|
||||
while(s != NULL) {
|
||||
(*L).tail = s;
|
||||
s = s->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
(*L).len += count;
|
||||
|
||||
return OK;
|
||||
}
|
||||
75
VisualC++/CourseBook/0405_WordList/ELinkList.h
Normal file
75
VisualC++/CourseBook/0405_WordList/ELinkList.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*=======================
|
||||
* 扩展的单链表(线性链表)
|
||||
*
|
||||
* 包含算法: 2.20
|
||||
========================*/
|
||||
|
||||
#ifndef ELINKLIST_H
|
||||
#define ELINKLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include <limits.h> // 提供一些极限常量
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/*
|
||||
* ████ 注意 ████
|
||||
*
|
||||
* 教材中的线性链表命名为LinkList,
|
||||
* 这里为了与单链表区分,故将其命名为ELinkList。
|
||||
* 线性链表可以理解成对普通链表的一种扩展。
|
||||
*/
|
||||
|
||||
/* 线性链表元素类型定义 */
|
||||
typedef int ElemType;
|
||||
|
||||
/*
|
||||
* 线性链表结构
|
||||
*
|
||||
* 注:这里的线性链表存在头结点
|
||||
*/
|
||||
typedef struct LNode {
|
||||
ElemType data;
|
||||
struct LNode* next;
|
||||
} LNode, * Link, * Position;
|
||||
|
||||
/* 维护线性链表头尾指针及长度信息 */
|
||||
typedef struct {
|
||||
Link head, tail; // 分别指向线性链表中的头结点和尾结点
|
||||
int len; // 指示线性链表中数据元素的个数
|
||||
} ELinkList;
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 内存操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 内存分配
|
||||
*
|
||||
* 为线性链表申请一个结点,并存入指定的数据e。
|
||||
*
|
||||
*【备注】
|
||||
* static修饰的含义是该函数仅限当前文件内使用
|
||||
*/
|
||||
Status MakeNode(Link* p, ElemType e);
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表常规操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 初始化成功则返回OK,否则返回ERROR。
|
||||
*/
|
||||
Status InitList(ELinkList* L);
|
||||
|
||||
|
||||
/*━━━━━━━━━━━━━━━━━━━━━━ 链表扩展操作 ━━━━━━━━━━━━━━━━━━━━━━*/
|
||||
|
||||
/*
|
||||
* 向尾部添加
|
||||
*
|
||||
* 将s所指的一串结点链接在链表L后面
|
||||
*/
|
||||
Status Append(ELinkList* L, Link s);
|
||||
|
||||
#endif
|
||||
95
VisualC++/CourseBook/0405_WordList/HString.c
Normal file
95
VisualC++/CourseBook/0405_WordList/HString.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*=========================
|
||||
* 串的堆分配存储表示(堆串)
|
||||
*
|
||||
* 包含算法: 4.4
|
||||
==========================*/
|
||||
|
||||
#include "HString.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(HString* T, const char* chars) {
|
||||
int i, j;
|
||||
|
||||
// 求chars的长度
|
||||
i = (int) strlen(chars);
|
||||
|
||||
// 没有有效元素
|
||||
if(i == 0) {
|
||||
(*T).ch = NULL;
|
||||
(*T).length = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
// 存在有效元素时,需要分配存储空间
|
||||
(*T).ch = (char*) malloc(i * sizeof(char));
|
||||
if(!((*T).ch)) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
for(j = 0; j < i; j++) {
|
||||
(*T).ch[j] = chars[j];
|
||||
}
|
||||
|
||||
(*T).length = i;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 比较
|
||||
*
|
||||
* 比较串S和串T,返回比较结果。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrCompare(HString S, HString T) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < S.length && i < T.length; i++) {
|
||||
// 遇到不同的字符时,比较其大小
|
||||
if(S.ch[i] != T.ch[i]) {
|
||||
return S.ch[i] - T.ch[i];
|
||||
}
|
||||
}
|
||||
|
||||
return S.length - T.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* 复制
|
||||
*
|
||||
* 将串S复制到串T。
|
||||
*/
|
||||
Status StrCopy(HString* T, HString S) {
|
||||
int i;
|
||||
|
||||
if(S.length == 0) {
|
||||
(*T).ch = NULL;
|
||||
(*T).length = 0;
|
||||
} else {
|
||||
// 分配空间
|
||||
(*T).ch = (char*) malloc(S.length * sizeof(char));
|
||||
if(!(*T).ch) {
|
||||
exit(OVERFLOW);
|
||||
}
|
||||
|
||||
// 复制元素
|
||||
for(i = 0; i < S.length; i++) {
|
||||
(*T).ch[i] = S.ch[i];
|
||||
}
|
||||
|
||||
// 复制长度信息
|
||||
(*T).length = S.length;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
53
VisualC++/CourseBook/0405_WordList/HString.h
Normal file
53
VisualC++/CourseBook/0405_WordList/HString.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*=========================
|
||||
* 串的堆分配存储表示(堆串)
|
||||
*
|
||||
* 包含算法: 4.4
|
||||
==========================*/
|
||||
|
||||
#ifndef HSTRING
|
||||
#define HSTRING
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
|
||||
#include <string.h> // 提供strlen原型
|
||||
#include "Status.h" //**▲01 绪论**//
|
||||
|
||||
/*
|
||||
* 串的堆存储表示
|
||||
*
|
||||
* 注:有效元素从ch的0号单元开始存储
|
||||
*/
|
||||
typedef struct {
|
||||
char* ch; // 若是非空串,则按串长分配存储区,否则ch为NULL
|
||||
int length;
|
||||
} HString;
|
||||
|
||||
|
||||
/*
|
||||
* 初始化
|
||||
*
|
||||
* 构造一个值为chars的串T。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrAssign(HString* T, const char* chars);
|
||||
|
||||
/*
|
||||
* 比较
|
||||
*
|
||||
* 比较串S和串T,返回比较结果。
|
||||
*
|
||||
*【注】
|
||||
* 该操作属于最小操作子集
|
||||
*/
|
||||
Status StrCompare(HString S, HString T);
|
||||
|
||||
/*
|
||||
* 复制
|
||||
*
|
||||
* 将串S复制到串T。
|
||||
*/
|
||||
Status StrCopy(HString* T, HString S);
|
||||
|
||||
#endif
|
||||
7
VisualC++/CourseBook/0405_WordList/TestData.txt
Normal file
7
VisualC++/CourseBook/0405_WordList/TestData.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Êé ºÅ Êé Ãû
|
||||
005 Computer Data Structures
|
||||
010 Introduction to Data Structures
|
||||
023 Fundamentals of Data Structures
|
||||
034 The Design and Analysis of Computer Algorithms
|
||||
050 Introduction to Numerical Analysis
|
||||
067 Numerical Analysis
|
||||
27
VisualC++/CourseBook/0405_WordList/WordList-main.c
Normal file
27
VisualC++/CourseBook/0405_WordList/WordList-main.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <stdio.h> // 提供system原型
|
||||
#include "WordList.h" //**▲04 串**//
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
FILE* fp;
|
||||
char line[MaxLineLen];
|
||||
|
||||
char* bookinfo = "TestData.txt"; // 书目文件名
|
||||
char* bookidx = "BookIdx.txt"; // 关键词索引文件名
|
||||
|
||||
// 创建索引表
|
||||
Main(bookinfo, bookidx);
|
||||
|
||||
// 显示索引表到屏幕
|
||||
if((fp = fopen(bookidx, "r"))!=NULL) {
|
||||
printf("---------索引表生成功!---------\n\n");
|
||||
|
||||
while(feof(fp)==FALSE) {
|
||||
fgets(line, MaxLineLen, fp);
|
||||
printf("%s", line);
|
||||
}
|
||||
} else {
|
||||
printf("---------未发现索引表!---------\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
308
VisualC++/CourseBook/0405_WordList/WordList.c
Normal file
308
VisualC++/CourseBook/0405_WordList/WordList.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*===========================================
|
||||
* 索引表
|
||||
*
|
||||
* 包含算法: 4.9、4.10、4.11、4.12、4.13、4.14
|
||||
============================================*/
|
||||
|
||||
#include "WordList.h" //**▲04 串**//
|
||||
|
||||
/*
|
||||
* ████████ 算法4.9 ████████
|
||||
*
|
||||
* 从文件bookinfo中读取书目信息,并依此创建相应的关键词索引表,然后将索引表写入文件bookidx。
|
||||
*/
|
||||
void Main(char* bookinfo, char* bookidx) {
|
||||
FILE* f, * g;
|
||||
char head[MaxLineLen]; // 书目的表头信息(未使用)
|
||||
IdxListType idxlist; // 关键词索引表
|
||||
ElemType bno; // 书号
|
||||
int count;
|
||||
|
||||
// 以“只读”模式打开书目文件
|
||||
if((f = fopen(bookinfo, "r")) != NULL) {
|
||||
|
||||
// 以“只写”模式打开索引文件
|
||||
if((g = fopen(bookidx, "w")) != NULL) {
|
||||
|
||||
// 初始化索引表
|
||||
InitIdxList(&idxlist);
|
||||
|
||||
// 跳过文件第一行
|
||||
fgets(head, MaxLineLen, f);
|
||||
|
||||
count = 0;
|
||||
|
||||
// 如果未到文件结尾,则一直读文件
|
||||
while(feof(f) == FALSE && count < MaxBookNum) {
|
||||
|
||||
// 从文件f读入一个书目信息到书目缓冲区gBuf
|
||||
GetLine(f);
|
||||
|
||||
// 从gBuf提取关键词到词表gWdList,书号存入bno
|
||||
ExtractKeyWord(&bno);
|
||||
|
||||
// 将书号及对应的关键词插入索引表idxlist
|
||||
InsIdxList(&idxlist, bno);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
// 向文件g中写入索引表数据
|
||||
PutText(g, idxlist);
|
||||
|
||||
fclose(g);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 初始化索引表
|
||||
*
|
||||
*【注】
|
||||
* 教材中将索引表表头置为空串,但这里设定了一个有意义的表头
|
||||
*/
|
||||
void InitIdxList(IdxListType* idxlist) {
|
||||
// 索引表的表头信息
|
||||
char* chars = "关键词 书号索引";
|
||||
IdxTermType e;
|
||||
|
||||
// 初始化表头信息
|
||||
StrAssign(&(e.key), chars);
|
||||
|
||||
// 初始化书号索引链表
|
||||
InitList(&(e.bnolist));
|
||||
|
||||
(*idxlist).item[0] = e;
|
||||
|
||||
// 表头为第0条信息
|
||||
(*idxlist).last = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 从文件f中读取一条书目信息存入书目缓冲区gBuf。
|
||||
*/
|
||||
void GetLine(FILE* f) {
|
||||
// 读取一行数据,存入缓冲区gBuf
|
||||
fgets(gBuf, MaxLineLen, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* 从缓冲区gBuf中提取书名关键词到词表gWdList,书号存入bno。
|
||||
*/
|
||||
void ExtractKeyWord(ElemType* bno) {
|
||||
char delim[] = {'-', ' ', '\r', '\n', '\t'}; // 分隔符
|
||||
char* title; // 书名
|
||||
char* token; // 从书名中分解出的关键词
|
||||
|
||||
// 分解书目字符串,将书号存入bno(十进制),并用title指向剩下的字符串(书名)
|
||||
*bno = (int) strtol(gBuf, &title, 10);
|
||||
|
||||
// 将书名的由大写变小写
|
||||
strlwr(title);
|
||||
|
||||
// 清空关键词词表
|
||||
gWdList.last = 0;
|
||||
|
||||
// 分解关键词
|
||||
for(token = strtok(title, delim); token != NULL; token = strtok(NULL, delim)) {
|
||||
// 如果该关键词是常用词,则忽略它
|
||||
if(isCommonWords(token) == TRUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 记下从书名中提取的关键词
|
||||
gWdList.item[gWdList.last++] = token;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.10 ████████
|
||||
*
|
||||
* 将书号bno对应的书名中的关键词按词典顺序插入到索引表idxlist。
|
||||
*/
|
||||
Status InsIdxList(IdxListType* idxlist, int bno) {
|
||||
int i, j;
|
||||
Boolean boo;
|
||||
HString wd;
|
||||
|
||||
if(gWdList.last <= 0) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 遍历书号bno对应的书名中的所有关键词
|
||||
for(i = 0; i < gWdList.last; i++) {
|
||||
// 获取待插入的关键词
|
||||
GetWord(i, &wd);
|
||||
|
||||
// 判断该关键词是否已经位于索引表中
|
||||
j = Locate(*idxlist, wd, &boo);
|
||||
|
||||
// 如果该关键词不在索引表中,则需要插入关键词
|
||||
if(boo == FALSE) {
|
||||
// 将关键词wd插入到索引表
|
||||
InsertNewKey(idxlist, j, wd);
|
||||
}
|
||||
|
||||
// 在关键词已存在的情形下,插入书号
|
||||
if(!InsertBook(idxlist, j, bno)) {
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.11 ████████
|
||||
*
|
||||
* 用wd返回词表gWdList中第i个关键词。
|
||||
*/
|
||||
void GetWord(int i, HString* wd) {
|
||||
if(i < 0 || i > gWdList.last - 1) {
|
||||
StrAssign(wd, "");
|
||||
} else {
|
||||
StrAssign(wd, gWdList.item[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.12 ████████
|
||||
*
|
||||
* 查询在索引表idxlist中是否存在与wd相等的关键词。
|
||||
* 若存在,则返回wd在词表中的位置,并置b为TRUE。
|
||||
* 若不存在,则返回wd应插入的位置,并置b为FALSE。
|
||||
*/
|
||||
int Locate(IdxListType idxlist, HString wd, Boolean* b) {
|
||||
int i, m = -1;
|
||||
|
||||
/*
|
||||
* 在索引表idxlist中查找关键词wd是否存在
|
||||
* 注:0号单元存储了表头信息
|
||||
*/
|
||||
for(i = idxlist.last; i > 0 && (m = StrCompare(idxlist.item[i].key, wd)) > 0; i--) {
|
||||
}
|
||||
|
||||
// 如果找到了关键词wd
|
||||
if(m == 0) {
|
||||
*b = TRUE;
|
||||
return i;
|
||||
} else {
|
||||
*b = FALSE;
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.13 ████████
|
||||
*
|
||||
* 在索引表的索引i(>=0)处插入关键词wd,并初始化书号索引的链表为空表。
|
||||
*/
|
||||
void InsertNewKey(IdxListType* idxlist, int i, HString wd) {
|
||||
int j;
|
||||
|
||||
/*
|
||||
* 索引项后移
|
||||
* 注:0号单元存储了表头信息
|
||||
*/
|
||||
for(j = (*idxlist).last; j >= i; j--) {
|
||||
(*idxlist).item[j + 1] = (*idxlist).item[j];
|
||||
}
|
||||
|
||||
// 插入索引项
|
||||
StrCopy(&((*idxlist).item[i].key), wd);
|
||||
|
||||
// 初始化书号索引链表
|
||||
InitList(&((*idxlist).item[i].bnolist));
|
||||
|
||||
// 索引数目增一
|
||||
(*idxlist).last++;
|
||||
}
|
||||
|
||||
/*
|
||||
* ████████ 算法4.14 ████████
|
||||
*
|
||||
* 为索引表在索引i(>0)处的关键词插入书号。
|
||||
*/
|
||||
Status InsertBook(IdxListType* idxlist, int i, ElemType bno) {
|
||||
Link p;
|
||||
|
||||
// 内存分配失败
|
||||
if(MakeNode(&p, bno) == FALSE) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// 插入新的书号索引
|
||||
Append(&((*idxlist).item[i].bnolist), p);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 将生成的索引表idxlist输出到文件g。
|
||||
*/
|
||||
void PutText(FILE* g, IdxListType idxlist) {
|
||||
int i, j, m, n;
|
||||
Link p;
|
||||
HString S;
|
||||
ELinkList L;
|
||||
|
||||
if(idxlist.last <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先输出表头信息
|
||||
S = idxlist.item[0].key;
|
||||
for(m = 0; m < S.length; m++) {
|
||||
fprintf(g, "%c", S.ch[m]);
|
||||
}
|
||||
fprintf(g, "\n");
|
||||
|
||||
// 输出索引信息
|
||||
for(i = 1; i <= idxlist.last; i++) {
|
||||
// 1.输出关键词
|
||||
S = idxlist.item[i].key;
|
||||
for(m = 0; m < S.length; m++) {
|
||||
fprintf(g, "%c", S.ch[m]);
|
||||
}
|
||||
|
||||
// 2.输出空格
|
||||
for(j = 1; j <= 18 - idxlist.item[i].key.length; j++) {
|
||||
fprintf(g, " ");
|
||||
}
|
||||
|
||||
// 3.输出书号索引
|
||||
L = idxlist.item[i].bnolist;
|
||||
for(n = 1, p = L.head->next; n <= L.len; n++) {
|
||||
fprintf(g, "%03d", p->data);
|
||||
p = p->next;
|
||||
if(p) {
|
||||
fprintf(g, ",");
|
||||
}
|
||||
}
|
||||
|
||||
// 4.输出换行
|
||||
fprintf(g, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 判断str是否为常用词
|
||||
static Status isCommonWords(char* str) {
|
||||
int i;
|
||||
|
||||
// 常用词词表,这些词汇会被排除在关键词之外
|
||||
WordListType words = {{"a", "an", "the", "of", "and", "is", "to", "as", "in", "for"}, 10};
|
||||
|
||||
// 查询常用词词表
|
||||
for(i = 0; i < words.last; i++) {
|
||||
// 对两字符串进行忽略大小写的比较
|
||||
if(strcmpi(str, words.item[i]) == 0) {
|
||||
// 如果该字符串是常用词,则返回TRUE
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user