建立图书馆书目索引表

使用线性表+串的基本操作实现给定顺序的数号及数目,生成对应的索引表

参考《数据结构》严蔚敏老师及网上代码,使用code block调试;

易错点:

1,添加新关键词到索引表中,需先顺序移动插入点之后的关键字及书号链表,此时插入点的关键字串内存地址仍和其后的相同,

     如果直接赋值新关键字到此地址,则会把其后的关键字也同时修改,所以需重新分配堆内存到带插入位置

2,插入一个新的额关键字后,需同时把此关键字位置对应的书号链表初始化并加入此关键字所在的书号

3,同一书目中连续出现多个相同的关键字时,只需要添加一个书号即可

上代码:调试中出现问题,请及时留言,谢谢


/**
*
* 建立图书馆书目索引表
*
* (从书目文件生成关键词索引表)
*
* 链表+串
*
* 1, 从书目文件中读入一个书目串
* 2, 从书目串中提取所有关键词插入词表
* 3, 对词表中每个关键词,在索引表中进行查找并作相应的插入操作
* 4, 循环上述步骤,直至书目文件读取完成
*
**/


#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>


using namespace std;

#define OK 1
#define ERROR 0

#define MaxBookNum    100        // 最大对100本书建立索引表
#define MaxKeyNum    50        // 索引表的最大容量
#define MaxLineLen    100        // 书目串的最大长度
#define MaxWordNum    10        // 词表的最大容量
#define MaxWordLen  30      // 每个单词最大长度

typedef unsigned char uchar;
typedef int ElemType;    // 书号索引
typedef int Status;

// 建立词表类型(顺序表)
typedef struct {
    uchar item[MaxWordNum][MaxWordLen];    // 词表字符串数组
    int last;        // 词表的长度
}WordListType;

/* 线性表中节点类型定义 */
typedef struct Node {
    ElemType bookno;
    struct Node *next;
}*Link;

/* 线性表类型定义 */
typedef struct {
    Link head;  // 头指针:指向线性链表的头结点的指针
    Link tail;  // 尾指针:指向线性链表的最后一个节点指针
    int  len;   // 标记线性链表的长度
} LinkList;        // 存放书号索引的单链表

// 关键词串
typedef struct {
    uchar *str;
    int len;
}HeapString;

// 定义索引表项节点结构
typedef struct {
    HeapString key;
    LinkList   bnolist;
}IdxItemType;

// 索引表结构(有序顺序表)
typedef struct {
    IdxItemType idxitem[MaxKeyNum + 1];
    int idxlast;
}IdxListType;

Status MakeNode(Link &p, const ElemType e)
{
    p = new struct Node;
    if (!p)
        return ERROR;
    p->bookno = e;
    p->next = NULL;
    return OK;
}

/* 针对线性表 */
/* 构建一个空的线性表 */
Status InitList(LinkList& L)
{
    /* 生成头结点 */
    Link head;
    if (MakeNode(head,-1))
    {
        L.head = L.tail = head;/* 线性表为空的条件:头指针==尾指针都指向头结点  */
        L.len = 0;
        return OK;
    } else
    {
        return ERROR;
    }
}


// 串最小操作子集
Status StrAssign(HeapString & T, uchar *str)
{
    if (T.str)
        delete [] T.str;    // 释放T原来的存储数据
    int len = strlen((const char*)str);
    uchar *newbase = new uchar[len];
    if (!newbase)
        return ERROR;
    T.str = newbase;
    memcpy(T.str, str, len);
    T.len = len;
    return OK;
}

// 串S复制到串T
Status StrCopy(HeapString&T, HeapString S)
{
    if (T.str)
        delete [] T.str;
    T.str = new uchar[S.len];
    if (!(T.str))
        return ERROR;
    memcpy(T.str, S.str, S.len);
    T.len = S.len;
    return OK;
}


int StrCompare(HeapString S, HeapString T)
{// S>T return 1
 // S == T return 0
 // S<T return -1
    for (int idx = 0; (idx < S.len) && (idx < T.len); idx++)
    {
        if (S.str[idx] != T.str[idx]) {
            return S.str[idx] - T.str[idx];
        }
    }
    return S.len - T.len;
}

Status AppendList(LinkList &L, Link s)
{
    int i = 1;

    if (!s)
        return ERROR;
    if (L.tail->bookno == s->bookno) {
    // 同一数目相同的关键字只添加一次书号
        return OK;
    }
    L.tail->next = s;   // s串添加到L的尾节点,
    L.tail = s;         // 更新L的尾节点
    L.len += i;         // 更新L的长度
    return OK;
}


uchar buf[MaxLineLen];    // 书目串缓冲区
WordListType wdlist; // 词表


// 从词表中返回第i个关键词
void GetWord(int i, HeapString &wd)
{
    uchar *p = wdlist.item[i];
    StrAssign(wd, p);
}

// 在索引表中查找是否存在于wd相同的关键词,若存在,则返回其在索引表中位置,并置b为true
// 若不存在,返回将要插入此关键词的位置,并置b为false
int Locate(IdxListType idxlist, HeapString wd, bool &b)
{
    int m;
    int idx;
    /* 查找待插入关键词是否已在索引表中 */
    if (0 == idxlist.idxlast) {
        b = false;
        return 0;
    }
    for (idx = idxlist.idxlast - 1; idx >= 0; idx--) {
        if ((m = StrCompare(idxlist.idxitem[idx].key, wd)) > 0) {
            continue;
        } else {
            break;
        }
    }
    if (0 == m) {
        b = true;
        return idx;
    } else {
        b = false;
        return idx + 1;
    }
}

// 在索引表第i项上插入新的关键词wd,并初始化书号索引的链表为空表
void InsertNewKey(IdxListType &idxlist, int i, HeapString wd)
{
    for (int jdx = idxlist.idxlast - 1; jdx >= i; jdx--) {    // 向后移动i之后的项
        idxlist.idxitem[jdx + 1] = idxlist.idxitem[jdx];    // 拷贝过程中把关键字及书号链表全部拷贝走
    }
    idxlist.idxitem[i].key.str = NULL;
    idxlist.idxitem[i].key.len = 0;            // 需重新分配新关键字堆内存
    StrCopy(idxlist.idxitem[i].key, wd);
    InitList(idxlist.idxitem[i].bnolist);    // 需清除拷贝过程中带来的书号链表
    idxlist.idxlast++;
}

// 在索引表的第i项中插入书号为no的索引
Status InsertBookNo(IdxListType &idxlist, int i, ElemType no)
{
    Link p;

    if (!MakeNode(p,no))
        return ERROR;
    AppendList(idxlist.idxitem[i].bnolist, p);
    return OK;
}

// 初始化索引表,置索引表为空表,且在idxitem[0]设置为空串
void InitIdxList(IdxListType &idxlist)
{
    idxlist.idxlast = 0;
    for (int idx = 0; idx < (MaxKeyNum + 1); idx++) {
        InitList(idxlist.idxitem[idx].bnolist);
        idxlist.idxitem[idx].key.str = NULL;
        idxlist.idxitem[idx].key.len = 0;
    }
}

// 从文件file中读取一个书目信息到书目串缓冲区buf
void GetLine(FILE *file)
{
    fgets((char *)buf, MaxLineLen, file);
}

// 从书目串缓冲区提取关键词到词表wdlist,书号存入bno
void ExtractKeyWord(ElemType &bno)
{
    uchar IgnoreChar[][10] = {"a","to","of","the","and","not","or","if" };
    bool  wordstartflag = false;
    bool  ignoreflag = false;
    int idx = 0;
    int wordcnt = 0;
    wdlist.last = 0;
    while (buf[idx] != '\n' && buf[idx] != '\0') {    /* 提取书号字符 */
        if (wordstartflag) {    /* 开始接收有效字符 */
            if (buf[idx] == ' ') {    /* 开始下一个单词接收 */
                wordstartflag = false;
                wdlist.item[wdlist.last][wordcnt++] = 0;    /* 每个单词添加结束符 */
                for (int jdx = 0; jdx < (sizeof(IgnoreChar)/sizeof(IgnoreChar[0])); jdx++) {
                    if (0 == strcmp((const char*)(wdlist.item[wdlist.last]), (const char*)(IgnoreChar[jdx]))) {    /* 忽略 */
                        ignoreflag = true;
                        break;
                    }
                }
                if (!ignoreflag) {
                    wdlist.last++;
                }
                ignoreflag = false;
                wordcnt = 0;
            } else {    /* 非空格,添加到当前单词 */
                if (('A' <=buf[idx]) && (buf[idx] <= 'Z'))
                    wdlist.item[wdlist.last][wordcnt] = buf[idx] + 32;    /* 大写转小写 */
                else
                    wdlist.item[wdlist.last][wordcnt] = buf[idx];
                ++wordcnt;
                ++idx;
            }
        } else {
            /* 跳过各个单词之间的空格 */
            if (buf[idx] != ' ') {
                wordstartflag = true;
            } else {
                idx++;
            }
        }
    }
    wdlist.item[wdlist.last][wordcnt++] = 0;
    wdlist.last++;
    /* 提取书号 */
    int bookno = -1;
    if ((bookno = atoi((const char*)(wdlist.item[0]))) > 0)    /* 将书号字符串转换为int型 */
        bno = bookno;
}

// 将书号为bno的书名关键词按照字典顺序插入到索引表idxlist
Status InsIdxList(IdxListType &idxlist, ElemType bno)
{
    HeapString wd;
    bool b;
    int jdx;

    for (int idx = 1; idx < wdlist.last; idx++) {
        wd.str = NULL;
        GetWord(idx,wd);
        jdx = Locate(idxlist,wd,b);
        if (!b) {
            InsertNewKey(idxlist,jdx,wd);    // 插入新关键字
            InsertBookNo(idxlist,jdx,bno);  // 并把新关键字对应的书号保存到链表
        } else {
            if (!InsertBookNo(idxlist,jdx,bno))
                return ERROR;
        }
    }
    return OK;
}

// 将生成的索引表输出到文件g
void PutIdxList(FILE *file, IdxListType idxlist)
{
    Link p;
    for (int idx = 0; idx < idxlist.idxlast; idx++) {
        for (int jdx = 0; jdx < idxlist.idxitem[idx].key.len; jdx++) {

            putc(idxlist.idxitem[idx].key.str[jdx], file);
        }
        putc('\t', file);
        if (idxlist.idxitem[idx].key.len < 8)
            putc('\t', file);
        p = idxlist.idxitem[idx].bnolist.head->next;
        for (int k = 0; (p != NULL) && (k < idxlist.idxitem[idx].bnolist.len); k++) {
            fprintf(file, "%03d",p->bookno);
            putc(' ', file);
            p = p->next;
        }
        putc('\n', file);
    }
}



int main()
{
    FILE *f, *g;
    IdxListType idxlist;
    ElemType  bookno;
    #if 0    // 测试当前工作目录
    if ((f = fopen("123.txt", "w")))
    {
        getch();
    }
    #endif
    if ((f = fopen("BookInfo.txt", "r"))) {
        if ((g = fopen("BookIdx.txt", "w"))) {
            InitIdxList(idxlist);
            while (!feof(f)) {
                GetLine(f);        // 读入一个书目信息到buf
                ExtractKeyWord(bookno);
                InsIdxList(idxlist, bookno);
            }
            PutIdxList(g, idxlist);
            fclose(f);
            fclose(g);
        } else {
            cout << "open BookIdx.txt failed!" << endl;
        }
    } else {
        cout << "open BookInfo.txt failed!" << endl;
    }
}



题目采自 《数据结构题集》(c语言版)(严蔚敏`吴伟民)6.3 图书管理,最大的难度在于要求用B树对书号进行索引。 设计语言:C语言 编译环境: VC++6.0 里面包含完整的源程序和报告文档,程序为dos界面,有彩色菜单,对数据显示实现格化……本课程设计成绩为优秀。 源程序有注释,报告文档完全按要求,包括所用数据结构的描述与实现、算法的时空分析等都包括在内。 程序所能达到的功能 1图书采编入库(用B树对书号建立索引) 2清除库存 3图书借阅 4图书归还 5图书预约 6列出某著者全部著作名 7列出某种书的状态(包括图书基本信息和该书借者名单、 预约者名单) 8每次插入或删除一个关键字后以凹入显示B树的状态 9把一次会话过程中的全部人机对话记录入一个日志文件中 10在程序主界面显示当前系统时间 一、 需求分析 1. 书号和借阅证号、库存量、出版年份用整型示;书名用20位字符型数组,著者和借阅者姓名用30位字符型数组示;图书价格用浮点型示。图书入库时输入图书的书号、书名、著者、总量等完整信息,清除库存时输入图书书号,借阅和归还时输入书号和借阅者证号,姓名等信息,并记录系统时间为借书日期。 2. 借书和归还时显示图书的信息。插入、删除后用凹入显示以书号建立的B树状态。查看图书状态,以格显示图书的基本信息,借阅者名单和预约者名单。 ……………… 课程设计清单: base.h //全程常量、全局变量和公共函数等 btree.h //B树类型单元 library.h //书库类型单元 main.cpp //主程序 bookiofo.dat //图书信息文件 borrower.dat //借书者姓名文件 bespeaker.dat //预约者姓名文件 main.exe //编译得到的可执行文件 数据结构课程设计实验报告-图书管理.doc
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值