华中大数据结构课程设计-------基于查找表的单词检索软件--------静态表、动态表、哈希表...

大二时写的数据结构课程设计,好几个朋友的推荐,现在放到博客了,希望对大家有帮助!

 

 

 

任务书

p 设计内容

设计与实现静态查找表、基于二叉排序树的动态查找表及HASH表等三种中的任意两种查找表结构及其抽象数据类型;以一本英文电子书(如英文小说,科普读物或圣经之类的社会书籍,书的篇幅不少于2万次单词)作为单词文本数据来源,使用上述查找表ADT,通过读取电子书而建立对应的两种查找表,以单词作为关键字,单词在书籍中出现的次数及每次出现的页码,行号等信息作为查找表数据元素属性;通过理论与实际测试结果对比分析两种查找表性能。

p 设计要求

(1) 静态查找表ADT要求实现Create、Destroy、Search、Traverse等操作,另外静态查找表同时要求采用某种排序算法Sort对其排序,形成无序存储与有序表存储两种物理存储,并同时实现在有序表上的二分查找Search_Bin,且作为性能对比分析的一种情形。

(2) 动态查找表ADT要求实现InitDSTable、DestroyTable、SearchDSTable、InsertDSTable、DeleteDSTable、TraverseDSTable等操作,以二叉链表为物理存储结构。

(3)     HASH表要求实现InitHash、DestroyHash、SearchHash、InsertHash、DeleteHash、TraverseHash等操作,设计合理的HASH函数与冲突解决办法,并在报告中分析说明选择理由。

(4) 一个单词的多次出现可以由链表表示,形成类似于倒排索引的结构。查找表数据以文件形式保存,如果在程序重启动时能够从查找表文件恢复查找表,或界面友好,或增加了有意义的功能等,具有一定特色,则给予鼓励,酌情加分。但是,如果只实现了其中一种查找表,则综合成绩不超过75分。

 

引言

1.1    课题背景与意义

数据结构在计算机科学界至今没有标准的定义。个人根据各自的理解的不同而有不同的表述方法:

Sartaj Sahni在他的《数据结构、算法与应用》一书中称:“数据结构是数据对象,以及存在于该对象的实例和组成实 例的数据元素之间的各种联系。这些联系可以通过定义相关的函数来给出。”他将数据对象(data object)定义为“一个数据对象是实例或值的集合”。Clifford A.Shaffer在《数据结构与算法分析》一书中的定义是:“数据结构是 ADT(抽象数据类型Abstract Data Type) 的物理实现。”

Lobert L.Kruse在《数据结构与程序设计》一书中,将一个数据结构的设计过程分成抽象层、数据结构层和实现层。其中,抽象层是指抽象数据类型层,它讨论数据的逻辑结构及其运算,数据结构层和实现层讨论一个数据结构的表示和在计算机内的存储细节以及运算的实现。数据结构具体指同一类数据元素中,各元素之间的相互关系,包括三个组成成分,数据的逻辑结构,数据的存储结构和数据运算结构。

在日常工作和学习中,我们会遇到统计一个文章里面所包含的单词或者词语。然而现在这样的统计软件在网络上特别多,作为一个学计算机编程的学生,我觉得有必要了解一下其核心功能以及算法实现。通过此次设计,可以对上学期学习的数据结构课程的内容做一个总结,感受真正用上学过的算法思想,这对以后的学习以及工作也有很大的帮助。

1.2    重要意义

一般认为,一个数据结构是由数据元素依据某种逻辑联系组织起来的。对数据元素间逻辑关系的描述称为数据的逻辑结构;数据必须在计算机内存储,数据的存储结构是数据结构的实现形式,是其在计算机内的表示;此外讨论一个数据结构必须同时讨论在该类数据上执行的运算才有意义。

在许多类型的程序的设计中,数据结构的选择是一个基本的设计考虑因素。许多大型系统的构造经验表明,系统实现的困难程度和系统构造的质量都严重的依赖于是否选择了最优的数据结构。许多时候,确定了数据结构后,算法就容易得到了。有些时候事情也会反过来,我们根据特定算法来选择数据结构与之适应。不论哪种情况,选择合适的数据结构都是非常重要的。

    选择了数据结构,算法也随之确定,是数据而不是算法是系统构造的关键因素。这种洞见导致了许多种软件设计方法和程序设计语言的出现,面向对象的程序设计语言就是其中之一。

1.3    课程设计的主要研究工作

       在计算机科学中,数据结构是一门研究非数值计算的程序设计问题中计算机的操作对象(数据元素)以及它们之间的关系和运算等的学科,而且确保经过这些运算后所得到的新结构仍然是原来的结构类型。

“数据结构”作为一门独立的课程在国外是从1968年才开始设立的。 1968年美国唐·欧·克努特教授开创了数据结构的最初体系,他所著的《计算机程序设计技巧》第一卷《基本算法》是第一本较系统地阐述数据的逻辑结构和存储结构及其操作的著作。“数据结构”在计算机科学中是一门综合性的专业基础课。数据结构是介于数学、计算机硬件和计算机软件三者之间的一门核心课程。数据结构这一门课的内容不仅是一般程序设计(特别是非数值性程序设计)的基础,而且是设计和实现编译程序、操作系统、数据库系统及其他系统程序的重要基础。

计算机是一门研究用计算机进行信息表示和处理的科学。这里面涉及到两个问题:信息的表示,信息的处理 。 而信息的表示和组织又直接关系到处理信息的程序的效率。随着计算机的普及,信息量的增加,信息范围的拓宽,使许多系统程序和应用程序的规模很大,结构又相当复杂。因此,为了编写出一个“好”的程序,必须分析待处理的对象的特征及各对象之间存在的关系,这就是数据结构这门课所要研究的问题。众所周知,计算机的程序是对信息进行加工处理。在大多数情况下,这些信息并不是没有组织,信息(数据)之间往往具有重要的结构关系,这就是数据结构的内容。数据的结构,直接影响算法的选择和效率。

计算机解决一个具体问题时,大致需要经过下列几个步骤:首先要从具体问题中抽象出一个适当的数学模型,然后设计一个解此数学模型的算法(Algorithm),最后编出程序、进行测试、调整直至得到最终解答。寻求数学模型的实质是分析问题,从中提取操作的对象,并找出这些操作对象之间含有的关系,然后用数学的语言加以描述。计算机算法与数据的结构密切相关,算法无不依附于具体的数据结构,数据结构直接关系到算法的选择和效率。运算是由计算机来完成,这就要设计相应的插入、删除和修改的算法 。也就是说,数据结构还需要给出每种结构类型所定义的各种运算的算法。

数据是对客观事物的符号表示,在计算机科学中是指所有能输入到计算机中并由计算机程序处理的符号的总称。 数据元素是数据的基本单位,在计算机程序中通常作为一个整体考虑。一个数据元素由若干个数据项组成。数据项是数据的不可分割的最小单位。有两类数据元素:一类是不可分割的原子型数据元素,如:整数"5",字符 "N" 等;

另一类是由多个款项构成的数据元素,其中每个款项被称为一个数据项。例如描述一个学生的信息的数据元素可由下列6个数据项组成。其中的出生日期又可以由三个数据项:"年"、"月"和"日"组成,则称"出生日期"为组合项,而其它不可分割的数据项为原子项。关键字指的是能识别一个或多个数据元素的数据项。若能起唯一识别作用,则称之为 "主" 关键字,否则称之为 "次" 关键字。数据对象是性质相同的数据元素的集合,是数据的一个子集。数据对象可以是有限的,也可以是无限的。

数据处理是指对数据进行查找、插入、删除、合并、排序、统计以及简单计算等的操作过程。在早期,计算机主要用于科学和工程计算,进入八十年代以后,计算机主要用于数据处理。据有关统计资料表明,现在计算机用于数据处理的时间比例达到80%以上,随着时间的推移和计算机应用的进一步普及,计算机用于数据处理的时间比例必将进一步增大。

 

 

系统需求分析与总体设计

2.1    系统需求分析

对单词数量不少于2万字的英文小说进行字符统计,用三种数据结构来实现,分别是基于顺序表的实现、基于动态查找表以二叉搜索树为结构来实现、基于HASH表的实现。抽象数据类型由单词、出现次数、页码、行数组成。计算结果以文本文件的形式保存到本地目录。以QT为用户界面,以C语言为编程语言。

2.2    系统总体设计

(1)    首先用户通过打开文件或者复制粘贴的方式把要分析的内容放在用户界面上的文本框。文本框的内容用户可以自己输入或更改,完成后通过相应的按钮进行计算并显示。由于有三种数据结构来实现,因此需要把计算内容分别显示。

(2)    基于顺序表的实现有两种,有序存储结构和无序存储结构。给用户提供两个按钮来相应两种结构的结果输出。创建有序存储先从文本内容里面取单词,把取单词的部分写成单独的函数,以便后序继续使用此函数来取单词,减少代码量。然后从现有的存储结构里面进行查找,如果找到了则单词数目加一,否则进行插入。查找函数以折半查找算法为核心,作为与无序表性能对比分析的一种情形。为了更好的显示出两种存储结构的优缺点,在这些函数运行时进行计时,当所有单词统计出来以后,把总时间显示到界面,以便用户对比分析结果。表创建完成后进行遍历输出,输出的内容有单词内容,单词出现次数、单词出现的页码以及行数,所以以表格的形式在界面上进行显示。

(3)    基于动态查找表以二叉搜索树为结构来实现。首先从用户输入的内容里面进行读取单词,然后在现有的数据里面进行查找,如果没有找到则进行创建。给用户提供三种遍历方式,前序、中序、后序。同样,在此部分程序运行时进行计时,最后结果在界面上显示,以便进行对比分析。

(4)    基于HASH表的实现,以每一个单词的第一与第二个字母的ASCLL值的和作为哈希值进行创建,以线性探索来处理冲突,哈希表长度为52。在此部分程序运行时进行计时,最后把结果以表格的形式显示在界面上。

(5)    计算并输出完成后,用户可以保存计算结果,保存的类型有txt、doc。保存位置由用户决定,用户打开对应的文件夹并输入文件名以后进行输出。

(6)    提供搜索功能,输入单词以后进行查找,找到单词以后进行定位,并使用QT内部函数给单词染色并突出显示。

(7)    用户界面上的所有按钮可以用对应的快捷键来控制。QT界面引用CSS样式表来设置界面颜色,总共提供四种风格。

程序整体流程图为如下:

 

图 2-1 系统整体运行流程图

系统详细设计

3.1    有关数据结构的定义

一共有四种数据结构,顺序存储结构、二叉树存储结构、HASH表存储结构、行页数存储结构、高频词汇存储结构。

(1)顺序存储结构

包含单词内容、单词出现次数、行数、页数,详细如下表:

表3-1 顺序存储结构数据类型

数据项

数据类型

名称

单词内容

Char []

word

出现次数

Int

count

行、页数

row_next *

row_head

顺序表的逻辑结构:

图 3-1  顺序表的逻辑结构

(1)二叉树存储结构

包含单词内容、单词出现次数、指向行页数的指针、指向左右结点的指针,详细如下表:

表 3-2 二叉树存储结构数据类型

数据项

数据类型

名称

单词内容

Char []

word

出现次数

Int

count

行、页数

row_next *

row_head

左孩子结点

struct DtList *

Lchild

右孩子结点

struct DtList *

Rchild

 二叉树逻辑存储结构如下图:

图 3-2 二叉树逻辑存储结构

(1)HASH表存储结构

包含单词内容、单词出现次数、指向行页数的指针, 详细如下表:

表 3-3 HASH表存储结构类型

数据项

数据类型

名称

单词内容

Char []

word

出现次数

Int

count

行、页数

row_next *

row_head

指向下一个结点的指针

struct Link_Node *

next

 HASH表逻辑存储结构如下图:

(1)行页数存储结构

包含行数、页数、指向下一个结点的指针,详细如下表:

表 3-4 行页存储结构类型

数据项

数据类型

名称

行数

Int

row

页数

Int

page

指向下一个结点的指针

struct row_next *

next

 

行页结构逻辑存储结构如下图:

(1)高频词汇存储结构

包含单词内容、出现次数,详细如下表:

表 3-5 高频词汇存储结构类型

数据项

数据类型

名称

单词

Char []

word

次数

int

count

 

 

高频词汇逻辑存储结构:

 

3.1    主要算法设计

这部分主要描述系统中的模块实现的流程,可采用文字配合流程图的方式表示各模块的算法思想及流程。

  1. 有序存储

首先初始化有序表,读取单词,从原有的顺序表中进行折半查找,如果找到了则进行单词数增加,并记录行页数。如果没有找到,则进行插入。流程图如下图:

  1. 无序存储

无序表创建过程与有序表一样,只是在查找的时候不能用折半查找来实现,只能从头开始一一比较。

  1. 二叉搜索树

二叉搜索树实现,首先获取内容取单词,创建二叉树,并在原来基础上查找结点,找到了则进行单词数目增加,并记录行页数。没有找到则进行插入。读取文件完成后进行输出,根据用户需求分别用三种遍历来输出,输出完成后计算出高频词汇,进行输出,最后记录运行总时间。流程图如下:

 

 

  1. HASH表

HASH表实现流程基本上也一样,实现的具体函数功能有所不一样。下图是整体实现过程:

系统实现与测试

4.1   系统实现

  1. 结构体

(1)  顺序存储结构

包含单词内容、单词出现次数、指向行页数的指针

      

 1  typedef struct
 2 
 3         {
 4 
 5                char word[MAX_CHARACTER];// 存储单词,不超过50个字符
 6 
 7                int count;               // 单词出现次数
 8 
 9                row_next *row_head;      //指向行页数的指针
10 
11                row_next *row_tail;      //指向最后一个(方便后序插入)
12 
13         } ElemType;
14 
15  
16 
17         typedef struct
18 
19         {
20 
21                ElemType *elem;      // 存储空间基址
22 
23                int length;          // 当前长度
24 
25                int listsize;        // 当前分配的存储容量
26 
27 } SqList;

 

(2)  搜索二叉树存储结构

包含单词内容、单词出现次数、指向行页数的指针、指向左右结点的指针

       
 1 typedef struct
 2 
 3         {
 4 
 5             char word[MAX_CHARACTER];  // 存储单词,不超过50个字符
 6 
 7             int count;                 // 单词出现次数
 8 
 9             row_next *row_head;        //指向行页数的指针
10 
11             row_next *row_tail;        //指向最后一个(方便后序插入)
12 
13         }DtElemType;                   //数据类型
14 
15  
16 
17         typedef struct DtList
18 
19         {
20 
21             DtElemType elem;                  //存储单词
22 
23             struct DtList *Lchild,*Rchild;    //左孩子以及右孩子
24 
25 }DtList;

 

(3)  HASH表存储结构

包含单词内容、单词出现次数、指向行页数的指针

      
 1  typedef struct Link_Node
 2 
 3         {
 4 
 5             char word[MAX_CHARACTER];    // 存储单词,不超过50个字符
 6 
 7             int count;                   //单词出现次数
 8 
 9             row_next *row_head;          //指向行页数的指针
10 
11             row_next *row_tail;          //指向最后一个(方便后序插入)
12 
13             struct Link_Node *next;
14 
15         }Link_Node;
16 
17         
18 
19         typedef struct Hash_Header
20 
21         {
22 
23             Link_Node *Link_head;      //哈希表头
24 
25 }Hash_Header;

 

(4)  行页数存储结构

包含行数、页数

       
typedef struct row_next{

            int row;                 //行数

            int page;                //页数

            struct row_next *next;  //指向下一个单词的行数

}row_next;

 

下面分别介绍具体实现的函数:

  1. 取单词  pickword

参数为文件地址,字符数组,行数。从文件地址所指的文件中依次读取一个字符,一律转换为小写字符保存在目的单词数组中。目的字符数组长度定义为50个字符,如果超过了进行返回。当遇到换行符时行数增加,遇到非字母字符时读取结束,返回读取到的单词。具体过程如下图:

 

  1. HASH_founc函数

实现HASH表时,哈希值用每一个单词的第一个字符与第二个字符的ascll码相加再与HASH表长度取余

  1. SqList_search_disorder无序表查找函数

实现无序表时,需要进行单词的搜索,但这时候很难实现有效的查找算法,只能从表头开始一一比较。

  1. SqListBSearch顺序表二分法查找

实现有序表时,需要进行单词的搜索,由于创建表时按照字母字典循序创建的,因此查找可以使用二分查找来实现,可以节省时间,效率高。

  1. SqListInit顺序表初始化

构造一个空的顺序表,分配内存,并初始化表长度,表大小。

  1. Dt_Free使用栈来实现释放二叉搜索树
  2. DtListInsert二叉树插入

首先找到插入位置,再分别判断是否有左右孩子,分情况分析最后创建结点并插入到对应位置。

  1. DtListPrint_preOrder前序遍历

用非递归算法来实现,使用栈来实现。

  1. InOrderTraverse中序遍历

递归算法来实现

  1. Dt_List_postOrder后序遍历

递归算法来实现

系统测试

 1.程序运行界面

2.有序表开始计算

3.无序表开始计算

4.

二叉搜索树中序遍历

5.

二叉搜索树前序遍

 

6.二叉搜索树—后序遍

7.HASH表

8.搜索功能

9.保存

 

 

10.保存文件演示

11.行页数

12.结果分析

 

 13.运行时间窗口演示

14.源代码演示窗口

15.帮助选项

 

 

源代码

 

  1 #ifndef FRMMAIN_H
  2 #define FRMMAIN_H
  3 
  4 #include <string.h>
  5 #include <QDialog>
  6 
  7 
  8 //函数结果状态代码
  9 #define TRUE    1
 10 #define FALSE   0
 11 #define OK      1
 12 #define ERROR   0
 13 #define OVERFLOW -2
 14 
 15 
 16 // 线性表的动态分配顺序存储结构
 17 #define LIST_INIT_SIZE 100  // 线性表存储空间的初始分配量
 18 #define LISTINCREMENT 10    // 线性表存储空间的分配增量
 19 #define HASH_TABLE_LEN  52  // HASH表长
 20 #define PAGE_LINE 26        //每个页行数
 21 
 22 
 23 const int MAX_CHARACTER = 50;       // 单词最大长度定为50(TUT.txt文中最长单词为production-education-researching)
 24 
 25 //行数结构
 26 typedef struct row_next{
 27     int row;
 28     int page;
 29     struct row_next *next;  //指向下一个单词的行数
 30 }row_next;
 31 
 32 // 顺序存储结构
 33 typedef struct
 34 {
 35     char word[MAX_CHARACTER];       // 存储单词,不超过50个字符
 36     int count;          // 单词出现次数
 37     row_next *row_head;            //行数
 38     row_next *row_tail;  //指向最后一个
 39 } ElemType;
 40 typedef struct
 41 {
 42     ElemType *elem;     // 存储空间基址
 43     int length;         // 当前长度
 44     int listsize;       // 当前分配的存储容量(以sizeof(ElemType)为单位)
 45 } SqList;
 46 
 47 
 48 // 线性存储结构
 49 typedef struct
 50 {
 51     char word[MAX_CHARACTER];       // 存储单词,不超过50个字符
 52     int count;          // 单词出现次数
 53     row_next *row_head;   //行数
 54     row_next *row_tail;   //
 55 }DtElemType;//数据类型
 56 
 57 typedef struct DtList
 58 {
 59     DtElemType elem;        //存储单词
 60     struct DtList *Lchild,*Rchild;  //左孩子以及右孩子
 61 }DtList;
 62 
 63 
 64 //HASH表结构
 65 typedef struct Link_Node
 66 {
 67     char word[MAX_CHARACTER];       // 存储单词,不超过50个字符
 68     int count;                      //计数
 69     row_next *row_head;             //行数
 70     row_next *row_tail;             //
 71     struct Link_Node *next;
 72 }Link_Node;
 73 
 74 //哈希表头
 75 typedef struct Hash_Header
 76 {
 77     Link_Node *Link_head;
 78 }Hash_Header;
 79 
 80 
 81 typedef struct High_count{
 82     char word[MAX_CHARACTER];
 83     int count;
 84 }High_count;
 85 
 86 
 87 
 88 class QLineEdit;
 89 namespace Ui {
 90 class frmMain;
 91 }
 92 
 93 class frmMain : public QDialog
 94 {
 95     Q_OBJECT
 96 
 97 public:
 98     explicit frmMain(QWidget *parent = 0);
 99     ~frmMain();
100     int SqListInit ( SqList *L );
101     int pickword ( FILE *f, char *fword ,int *row);
102     int SqListInsert ( SqList *L, int i, char *fword );
103     int SqList_insert_disorder(SqList *L,char *fword,int row);
104     int SqListBSearch ( SqList *L, char *sword, int &i );
105     int SqList_search_disorder(SqList *L, char *sword, int &i);
106     void SqListPrint(SqList *L);
107 
108     int DtListSearch(DtList *L, char *e,DtList **i);
109     int DtListInsert (DtList **L,char *fword,int row );
110     int DtListPrint_preOrder(DtList **L);
111     int Dt_Free(DtList **L);
112     int InOrderTraverse(DtList *L);
113     int Dt_List_postOrder(DtList *L);
114     int DtBiao_Creat(DtList **head);
115 
116     int HASH_func(char *word);
117     int hash_List_Search(Link_Node *L,char *fword,Link_Node **p );
118     int hash_List_Insert (Link_Node **L,char *fword ,int row);
119     void HASH_List_print(Hash_Header *L);
120 
121     void High_word(SqList *L);
122 
123 
124 protected:
125     bool eventFilter(QObject *obj, QEvent *event);
126     void mouseMoveEvent(QMouseEvent *e);
127     void mousePressEvent(QMouseEvent *e);
128     void mouseReleaseEvent(QMouseEvent *);
129 
130 private slots:
131     void on_btnMenu_Close_clicked();
132 
133     void on_btnMenu_Max_clicked();
134 
135     void on_btnMenu_Min_clicked();
136 
137     void on_pushButton_clicked();
138 
139     void on_pushButton_2_clicked();
140 
141     void on_pushButton_3_clicked();
142 
143     int OnBtnOpen();//打开文件
144 
145     void OnBtnSave();//保存计算结果
146 
147     int OnStart();//有序表--开始计算
148 
149     int SqList_disorder_start();//无序表--开始计算
150 
151     void textFind(); //查找文本
152 
153     void findNext(); //查找下一个
154 
155     void createPdf();//打印pdf
156 
157     void Dt_createPdf();//线性表打印pdf
158 
159     void hash_createPdf();//哈希表打印pdf
160 
161     int DtBiao_OnStart();//动态表开始计算按钮
162 
163     void clearTbWidget();//清空表格内容
164 
165     void Dt_Clear();//动态表表格清空
166 
167     void Dt_BtnSave();//动态表保存
168 
169     int DtBiao_Onstart_preOrder();//前序遍历
170 
171     int DtBiao_Onstart_PostOrder();//后序遍历
172 
173     int on_Btn_HASH_start();//HASH表开始计算按钮
174 
175     void hash_BtnSave();//HASH表保存
176 
177     void hash_Clear();//HASH表内容清空
178 
179 
180 
181 private:
182     Ui::frmMain *ui;
183 
184     QPoint mousePoint;
185     bool mousePressed;
186     bool max;
187     QRect location;
188 
189     void InitStyle();
190 
191     QLineEdit *lineEdit;
192 
193 };
194 
195 #endif // FRMMAIN_H

 

 

静态表

 

  1 //函数结果状态代码
  2 #define TRUE    1
  3 #define FALSE   0
  4 #define OK      1
  5 #define ERROR   0
  6 #define OVERFLOW -2
  7 
  8 
  9 // 线性表的动态分配顺序存储结构
 10 #define LIST_INIT_SIZE 100  // 线性表存储空间的初始分配量
 11 #define LISTINCREMENT 10    // 线性表存储空间的分配增量
 12 #define HASH_TABLE_LEN  52 // HASH表长
 13 
 14 
 15 const int MAX_CHARACTER = 50;       // 单词最大长度定为50(TUT.txt文中最长单词为production-education-researching)
 16 
 17 //行数结构
 18 typedef struct row_next{
 19     int row;
 20     struct row_next *next;  //指向下一个单词的行数
 21 }row_next;
 22 
 23 // 顺序存储结构
 24 typedef struct
 25 {
 26     char word[MAX_CHARACTER];       // 存储单词,不超过50个字符
 27     int count;          // 单词出现次数
 28     row_next *row_head;            //行数
 29 } ElemType;
 30 typedef struct
 31 {
 32     ElemType *elem;     // 存储空间基址
 33     int length;         // 当前长度
 34     int listsize;       // 当前分配的存储容量(以sizeof(ElemType)为单位)
 35 } SqList;
 36 
 37 
 38 /***************************
 39 
 40   主要功能函数___顺序表的实现
 41 
 42   *************************/
 43 
 44 int frmMain::OnStart()
 45 {
 46 int j=0,pronum=0;
 47 
 48     /*计算所消耗的时间---开始时间*/
 49     DWORDstart,stop,search_began,search_end,search_time=0,Insert_began,Insert_end,Insert_time=0, order_began,order_end,search_all_Time=0,insert_all_Time=0;
 50 
 51     start = GetTickCount();
 52 
 53     FILE *f1;
 54     FILE* fp=fopen("C:\Qt\src\QUI\linshi.txt","wb");
 55 
 56     QString str=ui->plainTextEdit->toPlainText();
 57     fprintf(fp,"%s",str.toStdString().c_str());
 58     fclose(fp);
 59 
 60     SqList L;               // 建立线性表
 61     SqListInit ( &L );          // 初始化顺序表
 62 
 63     char fword[MAX_CHARACTER];    // 使用fword数组保存文件中的单词
 64     fword[MAX_CHARACTER - 1] = '\0';
 65     int i = -1;             // 设置i为插入位置
 66     int row=1;
 67     row_next *row_p;
 68     f1=fopen("QtsrcQUIlinshi.txt","r");
 69 
 70     if(f1==NULL) return 0;
 71 
 72     while ( !feof ( f1 ) )      // 读文件未结束
 73     {
 74         int judge = pickword ( f1, fword ,&row); // 从f指向的文件中提取单词到fword中
 75 
 76         if ( -1 == judge )          // 数组越界时提示并退出
 77         {
 78             printf ( "存在单词字符长度超过数组界限\n" );
 79             return -1;
 80         }
 81 
 82         search_began=GetTickCount();
 83         if ( SqListBSearch ( &L, fword, i ) )   // i返回插入位置或单词在顺序表中位置
 84         {
 85             search_end=GetTickCount();
 86 
 87             if(search_time<(search_end-search_began)){
 88                 search_time=search_end-search_began;
 89 
 90             }
 91 
 92             search_all_Time=search_all_Time+(search_end-search_began);
 93 
 94             //qDebug() << tr("search:%1 ms").arg(search_time);
 95 
 96             // 在顺序表中找到该单词
 97             L.elem[i].count++;          // 单词出现次数加1
 98 
 99             row_p=(row_next *)malloc(sizeof(row_next));
100             row_p->row=row;
101             row_p->next=L.elem[i].row_head->next;
102             L.elem[i].row_head->next=row_p;
103         }
104         else
105         {
106             Insert_began=GetTickCount();
107 
108             // 顺序表中未找到该单词
109             SqListInsert ( &L, i, fword );      // 在第i个位置上插入
110             L.elem[i].row_head=(row_next *)malloc(sizeof(row_next));
111             L.elem[i].row_head->row=row;
112             L.elem[i].row_head->next=NULL;
113 
114             Insert_end=GetTickCount();
115 
116             if(Insert_time<Insert_end-Insert_began){
117                 Insert_time=Insert_end-Insert_began;
118             }
119 
120             insert_all_Time=insert_all_Time+(Insert_end-Insert_began);
121         }
122 
123     }
124 
125     /****程序运行结束,计算时间并显示****/
126     stop = GetTickCount();
127     //printf("time: %lld ms\n", stop - start);
128 
129     QString str1=tr("创建时间: %1 ms").arg(stop - start);
130     ui->TimeLine->setText(str1);
131     str1=tr("折半:%1 ms,最长:%2 ms").arg(search_all_Time).arg(search_time);
132     ui->Sq_search_ltimeline->setText(str1);
133     str1=tr("插入:%1 ms,最长:%2 ms").arg(insert_all_Time).arg(Insert_time);
134     ui->Sq_insert_timeline->setText(str1);
135 
136 
137     /*****进度条****/
138     for(i=0;i<=5;i++){
139         //ui->progressBar->setValue(pronum);
140         //Sleep(1);
141         for(pronum=0;pronum<=100;pronum++){
142             ui->progressBar->setValue(pronum);
143             //Sleep(1);
144         }
145     }
146 
147     //
148     ui->tableWidget->clearContents();
149     for(j=ui->tableWidget->rowCount();j>=0;j--){
150 
151         ui->tableWidget->removeRow(j);
152     }
153 
154     order_began=GetTickCount();
155 
156     // 将结果写入f2指向的文件中
157     SqListPrint ( &L );
158 
159     order_end=GetTickCount();
160 
161     str1=tr("遍历时间 : %1 ms").arg(order_end-order_began);
162     ui->Sq_order_line->setText(str1);
163 
164     i=0;
165     while(i<ui->tableWidget->rowCount()/3){
166        QComboBox *comBox = new QComboBox();
167         while(L.elem[i].row_head){
168             comBox->addItem(tr("%1").arg(L.elem[i].row_head->row));
169             L.elem[i].row_head=L.elem[i].row_head->next;
170         }
171         ui->tableWidget->setCellWidget(i,2,comBox);
172         i++;
173     }
174     free(L.elem);
175     L.length=0;
176     L.listsize=0;
177 
178 }
179 
180 int frmMain::SqList_disorder_start(){
181 
182     int j=0,pronum=0;
183 
184 
185     /*计算所消耗的时间---开始时间*/
186     DWORD start, stop,search_began,search_end,search_time=0,Insert_began,Insert_end,Insert_time=0,
187             order_began,order_end,search_all_time=0,insert_all_time=0;
188 
189     start = GetTickCount();
190 
191     FILE *f1;
192     FILE* fp=fopen("C:\Qt\src\QUI\linshi3.txt","wb");
193 
194     QString str=ui->plainTextEdit->toPlainText();
195     fprintf(fp,"%s",str.toStdString().c_str());
196     fclose(fp);
197 
198     SqList L;               // 建立线性表
199     SqListInit ( &L );          // 初始化顺序表
200 
201     char fword[MAX_CHARACTER];          // 使用fword数组保存文件中的单词
202     fword[MAX_CHARACTER - 1] = '\0';
203     int i = -1;             // 设置i为插入位置
204     int row=1;
205     row_next *row_p;
206 
207     f1=fopen("QtsrcQUIlinshi3.txt","r");
208 
209     if(f1==NULL) return 0;
210 
211     while ( !feof ( f1 ) )      // 读文件未结束
212     {
213         int judge = pickword ( f1, fword ,&row); // 从f指向的文件中提取单词到fword中
214 
215         if ( -1 == judge )          // 数组越界时提示并退出
216         {
217             printf ( "存在单词字符长度超过数组界限\n" );
218             return -1;
219         }
220 
221         search_began=GetTickCount();
222         if ( SqList_search_disorder ( &L, fword, i ) )   // i返回插入位置或单词在顺序表中位置
223         {
224             search_end=GetTickCount();
225 
226             if(search_time<(search_end-search_began)){
227                 search_time=search_end-search_began;
228             }
229 
230             search_all_time=search_all_time+(search_end-search_began);
231 
232             //qDebug() << tr("search:%1 ms").arg(search_time);
233 
234             // 在顺序表中找到该单词
235             L.elem[i].count++;          // 单词出现次数加1
236 
237 //            row_p=L.elem[i].row_head;
238 //            while(row_p){
239 //                row_p=row_p->next;
240 //            }
241             row_p=(row_next *)malloc(sizeof(row_next));
242             row_p->row=row;
243             row_p->next=L.elem[i].row_head->next;
244             L.elem[i].row_head->next=row_p;
245         }
246         else
247         {
248             Insert_began=GetTickCount();
249 
250             // 顺序表中未找到该单词
251             SqList_insert_disorder ( &L,fword ,row);      // 插入
252 
253             Insert_end=GetTickCount();
254 
255             if(Insert_time<Insert_end-Insert_began){
256                 Insert_time=Insert_end-Insert_began;
257             }
258 
259             insert_all_time=insert_all_time+(Insert_end-Insert_began);
260         }
261 
262     }
263 
264     /****程序运行结束,计算时间并显示****/
265     stop = GetTickCount();
266 
267 
268     QString str1=tr("创建时间: %1 ms").arg(stop - start);
269     ui->TimeLine->setText(str1);
270     str1=tr("查找:%1 ms,最长:%2 ms").arg(search_all_time).arg(search_time);
271     ui->Sq_search_ltimeline->setText(str1);
272     str1=tr("插入:%1 ms,最长:%2 ms").arg(insert_all_time).arg(Insert_time);
273     ui->Sq_insert_timeline->setText(str1);
274 
275 
276     /*****进度条****/
277     for(i=0;i<=5;i++){
278         //ui->progressBar->setValue(pronum);
279         //Sleep(1);
280         for(pronum=0;pronum<=100;pronum++){
281             ui->progressBar->setValue(pronum);
282             //Sleep(1);
283         }
284     }
285 
286     //
287     ui->tableWidget->clearContents();
288     for(j=ui->tableWidget->rowCount();j>=0;j--){
289 
290         ui->tableWidget->removeRow(j);
291     }
292 
293     order_began=GetTickCount();
294 
295     // 将结果
296     SqListPrint ( &L );
297 
298     order_end=GetTickCount();
299 
300     str1=tr("遍历时间 : %1 ms").arg(order_end-order_began);
301     ui->Sq_order_line->setText(str1);
302 
303     i=0;
304     while(i<ui->tableWidget->rowCount()/3){
305        QComboBox *comBox = new QComboBox();
306         while(L.elem[i].row_head){
307             comBox->addItem(tr("%1").arg(L.elem[i].row_head->row));
308             L.elem[i].row_head=L.elem[i].row_head->next;
309         }
310         ui->tableWidget->setCellWidget(i,2,comBox);
311         i++;
312     }
313 
314     free(L.elem);
315     L.length=0;
316     L.listsize=0;
317 
318 }
319 
320 /*********SqList_search_disorder**********/
321 
322 int frmMain::SqList_search_disorder ( SqList *L, char *sword, int &i )
323 {
324     if ( L->length == 0 )            // 当顺序表为空时
325     {
326         i = 0;                  // i返回单词插入位置
327         return ERROR;
328     }
329 
330     // 顺序表不空时,在顺序表L中查找元素sword,用i返回其在顺序表中的位置
331     int low = 0, high = L->length - 1;
332 
333     while ( low <= high )
334     {
335         if(strcmp ( L->elem[low].word, sword )==0){
336             i=low;
337             return OK;
338         }
339         else{
340             low++;
341         }
342     }
343 
344     return ERROR;           // 顺序表中不存在待查元素,函数返回值为0,i返回单词插入位置
345 }
346 
347 /***********SqList_insert_disorder************/
348 
349 // 顺序表的插入
350 int frmMain::SqList_insert_disorder( SqList *L,char *fword ,int row)
351 {
352     // 在顺序线性表L中第i个位置之前插入新的元素e
353     // i的合法值为1≤i≤L.Length + 1
354 //    if ( i < 0 || i > L->length )
355 //    {
356 //        //printf ( "i的值不合法!" );
357 //        return ERROR;   // i的值不合法
358 //    }
359 
360     int i=L->length;
361 
362     if ( L->length >= L->listsize )
363     {
364         // 当前存储空间已满,增加分配
365         ElemType *newbase = ( ElemType * ) realloc ( L->elem,
366                             ( L->listsize + LISTINCREMENT ) * sizeof ( ElemType ) );
367 
368         if ( !newbase )
369             return OVERFLOW;    // 存储分配失败
370 
371         L->elem = newbase;       // 新基址
372         L->listsize += LISTINCREMENT;    // 增加存储容量
373     }
374 
375     ElemType *p, *q;
376     q = &L->elem[i];
377 
378     strcpy ( q->word, fword );           // 复制fword中的字符到L->elem[i-1].word中
379     L->elem[i].count = 1;            // 设置计数初值为1
380     L->length++;                     // 表长增1
381 
382     L->elem[i].row_head=(row_next *)malloc(sizeof(row_next));
383     L->elem[i].row_head->row=row;
384     L->elem[i].row_head->next=NULL;
385 
386     return OK;
387 }
388 
389 
390 
391 
392 /****将结果显示到界面****/
393 void frmMain::SqListPrint(SqList *L){
394     int i=0,j=0;
395 
396     row_next *row_p;
397 
398     while(i<L->length){
399 
400        ui->tableWidget->insertRow(i);
401        ui->tableWidget->setItem(i,0,new QTableWidgetItem(L->elem[i].word));
402        ui->tableWidget->setItem(i,1,new QTableWidgetItem(QString("%1").arg(L->elem[i].count)));
403        //ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString("%1").arg(L->elem[i].row_head->row)));
404        //ui->tableWidget->update(i,2,new QTableWidgetItem(QString("%1").arg(L->elem[i].row_head->next->row)));
405 
406        i++;
407         }
408 }
409 
410 
411 // 顺序表的插入
412 int frmMain::SqListInsert ( SqList *L, int i, char *fword )
413 {
414     // 在顺序线性表L中第i个位置之前插入新的元素e
415     // i的合法值为1≤i≤L.Length + 1
416     if ( i < 0 || i > L->length )
417     {
418         //printf ( "i的值不合法!" );
419         return ERROR;   // i的值不合法
420     }
421 
422     if ( L->length >= L->listsize )
423     {
424         // 当前存储空间已满,增加分配
425         ElemType *newbase = ( ElemType * ) realloc ( L->elem,
426                             ( L->listsize + LISTINCREMENT ) * sizeof ( ElemType ) );
427 
428         if ( !newbase )
429             return OVERFLOW;    // 存储分配失败
430 
431         L->elem = newbase;       // 新基址
432         L->listsize += LISTINCREMENT;    // 增加存储容量
433     }
434 
435     ElemType *p, *q;
436     q = &L->elem[i];
437 
438     for ( p = &L->elem[L->length - 1]; p >= q; p-- )   // 插入位置之后元素逐个右移
439     {
440         * ( p + 1 ) = *p;
441     }
442 
443     strcpy ( q->word, fword );           // 复制fword中的字符到L->elem[i-1].word中
444     L->elem[i].count = 1;            // 设置计数初值为1
445     L->length++;                     // 表长增1
446     return OK;
447 }
448 
449 
450 // 顺序表二分法查找
451 int frmMain::SqListBSearch ( SqList *L, char *sword, int &i )
452 {
453     if ( L->length == 0 )            // 当顺序表为空时
454     {
455         i = 0;                  // i返回单词插入位置
456         return ERROR;
457     }
458 
459     // 顺序表不空时,在顺序表L中查找元素sword,用i返回其在顺序表中的位置
460     int low = 0, high = L->length - 1, mid = L->length;
461 
462     while ( low <= high )
463     {
464         mid = ( low + high ) / 2;
465         int k = strcmp ( L->elem[mid].word, sword );
466 
467         if ( k == 0 )           // 待查单词sword等于中间值,找到待查元素
468         {
469             i = mid;
470             return OK;          // 查找成功,函数返回值为1,用i返回所查元素在顺序表中的位置
471         }
472         else if ( k > 0 )        // 待查单词sword小于中间值,继续在前半区间进行查找
473         {
474             high = mid - 1;
475             i = low;
476         }
477         else                // 待查单词sword大于中间值,继续在后半区间进行查找
478         {
479             low = mid + 1;
480             i = high + 1;
481         }
482     }
483 
484     return ERROR;           // 顺序表中不存在待查元素,函数返回值为0,i返回单词插入位置
485 }
486 
487 int frmMain::pickword ( FILE *f, char *fword , int *row)       // 从f指向的文件中提取单词到fword中
488 {
489     char ch;                    // ch储存待检测字符
490 
491     for ( int j = 0 , flag = 0 ; !feof ( f ) ; )    // 逐个对字符进行检测,flag用于标记,为0时表示单词中无字母
492     {
493         if ( j >= MAX_CHARACTER )            // 判断数组是否越界
494         {
495             return -1;
496         }
497 
498         ch = fgetc ( f );              // 获取字符
499 
500 
501         if ( ch >= 'A' && ch <= 'Z' )         // 大写字符转小写保存在fword数组中
502         {
503             fword[j++] = ch + 32;
504             flag = 1;
505         }
506 
507         if ( ( ch >= 'a' && ch <= 'z' ) )     // 小写字符保存在fword数组中
508         {
509             fword[j++] = ch;
510             flag = 1;
511         }
512 
513         if(ch=='\n')
514         {
515             (*row)++;
516             //return 0;
517         }
518 
519         if ( '-' == ch && fword[j - 1] >= 'a' && fword[j - 1] <= 'z' )    // 若单词中带连字符,将连字符保存在fword数组中
520         {
521             fword[j++] = ch;
522         }
523 
524 
525 
526         if ( ! ( ( ch >= 'A' && ch <= 'Z' ) || ( ch >= 'a' && ch <= 'z' ) || '-' == ch )
527                 && flag == 1 )              // 过滤单词中的非字母字符
528         {
529             if ( fword[j - 1] == '-' )          // 排除类似于 a- 的单词
530                 fword[j - 1] = '\0';
531 
532             fword[j] = '\0';                // fword数组以'\0'结尾
533             return 0;
534         }
535 
536 
537     }
538 }
539 
540 
541 // 顺序表的初始化
542 int frmMain::SqListInit ( SqList *L )
543 {
544     // 构造一个空的顺序表L
545     L->elem = ( ElemType * ) malloc ( LIST_INIT_SIZE * sizeof ( ElemType ) );
546 
547     if ( !L->elem ) return OVERFLOW;     // 存储分配失败
548 
549     L->length = 0;
550     L->listsize = LIST_INIT_SIZE;
551     return OK;
552 }

 

 

搜索二叉树

 

  1 int frmMain::DtBiao_OnStart(){
  2 
  3     DWORD began,end;
  4 
  5     DtList *L;               // 建立线性表
  6     L=(DtList*)malloc(sizeof(DtList));//给头指针分配内存
  7     strcpy(L->elem.word," ");
  8     L->elem.count=0;
  9     L->Lchild=L->Rchild=NULL;//左右孩子初始化
 10 
 11     DtBiao_Creat(&L);        //创建二叉树
 12 
 13     began=GetTickCount();
 14     InOrderTraverse(L);     //中序遍历
 15     end=GetTickCount();
 16 
 17     QString str=tr("中序: %1 ms").arg(end-began);
 18     ui->Dt_order_line->setText(str);
 19 
 20     Dt_Free(&L);            //释放内存
 21 
 22 }
 23 
 24 int frmMain::DtBiao_Onstart_preOrder(){
 25 
 26     DWORD began,end;
 27 
 28     DtList *L;               // 建立线性表
 29     L=(DtList*)malloc(sizeof(DtList));//给头指针分配内存
 30     strcpy(L->elem.word," ");
 31     L->elem.count=0;
 32     L->Lchild=L->Rchild=NULL;//左右孩子初始化
 33 
 34     DtBiao_Creat(&L);           //创建二叉树
 35 
 36     began=GetTickCount();
 37     DtListPrint_preOrder(&L);   //前序遍历
 38     end=GetTickCount();
 39 
 40     QString str1=tr("前序: %1 ms").arg(end-began);
 41     ui->Dt_order_line->setText(str1);
 42 
 43     Dt_Free(&L);        //释放内存
 44 }
 45 
 46 int frmMain::DtBiao_Onstart_PostOrder(){
 47     DWORD began,end;
 48 
 49     DtList *L;               // 建立线性表
 50     L=(DtList*)malloc(sizeof(DtList));//给头指针分配内存
 51     strcpy(L->elem.word," ");
 52     L->elem.count=0;
 53     L->Lchild=L->Rchild=NULL;//左右孩子初始化
 54 
 55     DtBiao_Creat(&L);       //创建二叉树
 56 
 57     began=GetTickCount();
 58     Dt_List_postOrder(L);       //后序遍历
 59     end=GetTickCount();
 60 
 61     QString str1=tr("后序: %1 ms").arg(end-began);
 62     ui->Dt_order_line->setText(str1);
 63 
 64     Dt_Free(&L);    //释放内存
 65 }
 66 
 67 
 68 /*******二叉搜索树创建*********/
 69 int frmMain::DtBiao_Creat(DtList **head){
 70 
 71     DtList *L=*head;
 72 
 73     int j=0,pronum=0,y=0,flag=0;
 74 
 75     /*****tablewidget 表格内容清理******/
 76     ui->DtBiao_tableWidget->clearContents();
 77     for(j=ui->DtBiao_tableWidget->rowCount();j>=0;j--){
 78 
 79         ui->DtBiao_tableWidget->removeRow(j);
 80     }
 81 
 82 
 83     /*****进度条****/
 84     for(y=0;y<=2;y++){
 85         Sleep(1);
 86         for(pronum=0;pronum<=75;pronum++){
 87             ui->progressBar->setValue(pronum);
 88             //Sleep(1);
 89         }
 90     }
 91 
 92 
 93     /*计算所消耗的时间---*/
 94     DWORD   start_create,           /*创建哈希表开始时间*/
 95             stop_create,            /*创建哈希表结束时间*/
 96             search_began_dt,        /*搜索开始时间*/
 97             search_end_dt,          /*搜索结束时间*/
 98             search_time_dt=0,       /*搜索时间*/
 99             Insert_began_dt,        /*插入开始时间*/
100             Insert_end_dt,          /*插入结束时间*/
101             Insert_time_dt=0,       /*插入时间*/
102             search_all_time=0,      /*搜索总时间*/
103             insert_all_time=0;      /*插入总时间*/
104 
105     start_create = GetTickCount();
106 
107     FILE *f1;
108     FILE* fp=fopen("C:\Qt\src\QUI\linshi2.txt","wb");
109 
110     QString str=ui->DtBiao_Plaintext->toPlainText();
111     fprintf(fp,"%s",str.toStdString().c_str());     //把获取的内容写进本地txt文件里面
112     fclose(fp);
113 
114 
115 
116     char fword[MAX_CHARACTER];          // 使用fword数组保存文件中的单词
117     fword[MAX_CHARACTER - 1] = '\0';
118     DtList *i = NULL;             // 设置i为插入位置
119     int row=1;
120     row_next *row_p;
121 
122 
123     f1=fopen("QtsrcQUIlinshi2.txt","r");
124 
125     if(f1==NULL) return 0;
126 
127     while ( !feof ( f1 ) )      // 读文件未结束
128     {
129 
130         int judge = pickword ( f1, fword ,&row); // 从f指向的文件中提取单词到fword中
131 
132         if(flag==0){    //根结点
133             strcpy(L->elem.word,fword);
134             L->elem.count=1;
135             L->elem.row_head=(row_next *)malloc(sizeof(row_next));
136             L->elem.row_head->row=row%PAGE_LINE;
137             L->elem.row_head->page=row/PAGE_LINE+1;
138             L->elem.row_head->next=NULL;
139             L->elem.row_tail=L->elem.row_head;
140             flag=1;
141             continue;
142         }else{
143             if ( -1 == judge )          // 数组越界时提示并退出
144             {
145                 printf ( "存在单词字符长度超过数组界限\n" );
146                 return -1;
147             }
148 
149             if( -2 == judge ){
150                 continue;       //如果是换行符、文件结束符(-1/255)
151             }
152 
153             search_began_dt=GetTickCount();
154             if ( DtListSearch ( L, fword, &i ) )   // i返回插入位置或单词在线性表中位置
155             {
156                 search_end_dt=GetTickCount();
157 
158                 if(search_time_dt<(search_end_dt-search_began_dt)){
159                     search_time_dt=search_end_dt-search_began_dt;      //记录最长时间
160                 }
161 
162                 search_all_time=search_all_time+(search_end_dt-search_began_dt);//记录总搜索时间
163 
164                 // 在线性表中找到该单词
165                 i->elem.count++;          // 单词出现次数加1
166 
167                 row_p=(row_next *)malloc(sizeof(row_next));     //为新单词的行数页数分配空间
168                 row_p->row=row%PAGE_LINE;   //获取当前总行数,并计算赋值
169                 row_p->page=row/PAGE_LINE+1;//页数
170                 row_p->next=NULL;
171                 i->elem.row_tail->next=row_p;//添加到尾指针的next
172                 i->elem.row_tail=i->elem.row_tail->next;//尾指针指向最后
173             }
174             else
175             {
176                 Insert_began_dt=GetTickCount();
177                 // 顺序表中未找到该单词
178                 DtListInsert ( &L,fword,row );      // 插入
179 
180                 Insert_end_dt=GetTickCount();
181 
182                 if(Insert_time_dt<(Insert_end_dt-Insert_began_dt)){
183                     Insert_time_dt=Insert_end_dt-Insert_began_dt;//最长插入时间
184                 }
185                 //插入总时间
186                 insert_all_time=insert_all_time+(Insert_end_dt-Insert_began_dt);
187             }
188 
189         }
190 
191     }
192 
193     /****程序运行结束,计算时间并显示****/
194     stop_create = GetTickCount();
195 
196     //qDebug() << tr("shijian:%1 ms").arg(stop - start);
197     QString str1=tr("创建时间:%1 ms").arg(stop_create - start_create);
198     ui->DtBiao_TimeLine->setText(str1);
199     str1=tr("搜索:%1 ms,最长:%2 ms").arg(search_all_time).arg(search_time_dt);
200     ui->Dt_search_ltimeline->setText(str1);
201     str1=tr("插入:%1 ms,最长:%2 ms").arg(insert_all_time).arg(Insert_time_dt);
202     ui->Dt_insert_timeline->setText(str1);
203 
204 
205     /*****进度条****/
206     for(y=0;y<=1;y++){
207         Sleep(1);
208         for(pronum=0;pronum<=100;pronum++){
209             ui->progressBar->setValue(pronum);
210             //Sleep(1);
211         }
212     }
213 
214 
215 }
216 
217 
218 
219 /**free Destroy***
220 
221 使用栈来实现释放二叉搜索树
222 
223 *****************/
224 int frmMain::Dt_Free(DtList **L){
225     int top = -1;
226     DtList *stack[1000], *p, *q;
227     p = *L;
228     if (p == NULL){
229             free(*L);
230             return OK;
231     }
232     stack[++top] = *L;
233     while (top>-1) {
234             p = stack[top--];
235             q = p;
236             if (p->Rchild)  //释放右孩子
237                     stack[++top] = p->Rchild;
238             if (p->Lchild)  //是放左孩子
239                     stack[++top] = p->Lchild;
240             free(q);    //释放头节点
241     }
242 
243  return OK;
244 }
245 
246 /*******二叉树搜索********/
247 int frmMain::DtListSearch(DtList *T, char *e,DtList **i){
248         int top = -1;
249         DtList *stack[1000], *p;
250         p = T;
251         if(strcmp(p->elem.word,e)==0){
252             *i=p;
253             return 1;
254         }
255         //首元素进栈
256         stack[++top] = T;
257         while (top>-1) {
258                 p = stack[top--];
259                 if (p->Rchild) {
260                     if (strcmp(p->Rchild->elem.word,e) == 0){
261                         *i=p->Rchild;   //如果找到了则返回该结点地址
262                         return 1;
263                     }
264                 stack[++top] = p->Rchild;//不一样则进栈
265                 }
266                 if (p->Lchild) {
267                     if (strcmp(p->Lchild->elem.word,e) == 0){
268                         *i=p->Lchild;   ////如果找到了则返回该结点地址
269                         return 1;
270                     }
271                 stack[++top] = p->Lchild;//不一样则进栈
272                 }
273         }
274         //free(stack);
275 return 0;
276 }
277 
278 /********二叉树插入********/
279 int frmMain::DtListInsert(DtList **L, char *fword,int row){
280 
281     DtList *p=*L,*q;
282 
283     while(p){       //首先找到插入位置
284         q=p;
285         if(strcmp(p->elem.word,fword)<0){
286 
287             p=p->Rchild;
288             continue;
289         }
290         if(strcmp(p->elem.word,fword)>0){
291             p=p->Lchild;
292             continue;
293         }
294         if(strcmp(p->elem.word,fword)==0){
295             break;
296         }
297 
298     }
299     if(q->Lchild){      //如果有左孩子,且右孩子为空
300         if(q->Rchild==NULL){
301             q->Rchild=(DtList*)malloc(sizeof(DtList));
302             q->Rchild->Lchild=q->Rchild->Rchild=NULL;
303             strcpy(q->Rchild->elem.word,fword);
304             q->Rchild->elem.count=1;
305 
306             q->Rchild->elem.row_head=(row_next *)malloc(sizeof(row_next));
307             q->Rchild->elem.row_head->row=row%PAGE_LINE;
308             q->Rchild->elem.row_head->page=row/PAGE_LINE+1;
309             q->Rchild->elem.row_head->next=NULL;
310             q->Rchild->elem.row_tail=q->Rchild->elem.row_head;
311             return 1;
312         }
313     }
314     if(q->Rchild){      //如果有右孩子,且左孩子为空
315         if(q->Lchild==NULL){
316             q->Lchild=(DtList*)malloc(sizeof(DtList));
317             q->Lchild->Lchild=q->Lchild->Rchild=NULL;
318             strcpy(q->Lchild->elem.word,fword);
319             q->Lchild->elem.count=1;
320 
321             q->Lchild->elem.row_head=(row_next *)malloc(sizeof(row_next));
322             q->Lchild->elem.row_head->row=row%PAGE_LINE;
323             q->Lchild->elem.row_head->page=row/PAGE_LINE+1;
324             q->Lchild->elem.row_head->next=NULL;
325             q->Lchild->elem.row_tail=q->Lchild->elem.row_head;
326             return 1;
327         }
328     }
329     if(q->Lchild==NULL && q->Rchild==NULL){     //如果是叶子结点
330 
331         if(strcmp(q->elem.word,fword)<0){       //插入到左孩子
332             q->Rchild=(DtList*)malloc(sizeof(DtList));
333             q->Rchild->Lchild=q->Rchild->Rchild=NULL;
334             strcpy(q->Rchild->elem.word,fword);
335             q->Rchild->elem.count=1;
336 
337             q->Rchild->elem.row_head=(row_next *)malloc(sizeof(row_next));
338             q->Rchild->elem.row_head->row=row%PAGE_LINE;
339             q->Rchild->elem.row_head->page=row/PAGE_LINE+1;
340             q->Rchild->elem.row_head->next=NULL;
341             q->Rchild->elem.row_tail=q->Rchild->elem.row_head;
342             return 1;
343         }
344         else{       //插入到右孩子
345             q->Lchild=(DtList*)malloc(sizeof(DtList));
346             q->Lchild->Lchild=q->Lchild->Rchild=NULL;
347             strcpy(q->Lchild->elem.word,fword);
348             q->Lchild->elem.count=1;
349 
350             q->Lchild->elem.row_head=(row_next *)malloc(sizeof(row_next));
351             q->Lchild->elem.row_head->row=row%PAGE_LINE;
352             q->Lchild->elem.row_head->page=row/PAGE_LINE+1;
353             q->Lchild->elem.row_head->next=NULL;
354             q->Lchild->elem.row_tail=q->Lchild->elem.row_head;
355             return 1;
356         }
357     }
358 
359     return 0;
360 }
361 
362 /*********preOrder********/
363 int frmMain::DtListPrint_preOrder(DtList **Q){
364     DtList *stack[1000],*p,*L=*Q;
365     long all_count=0;
366     int top=-1,i=0,HIGH_LENTH=100,j;
367     High_count high_word[HIGH_LENTH],*r,*q;     //高频词汇数组
368 
369     while(i<HIGH_LENTH){
370         high_word[i].count=0;       //初始化
371         i++;
372     }
373 
374     i=0;
375     p=L;
376     stack[++top]=L;     //首元素进栈
377 
378     while (top>-1) {
379         p = stack[top--];
380         ui->DtBiao_tableWidget->insertRow(i);//插入新行
381         ui->DtBiao_tableWidget->setItem(i,0,new QTableWidgetItem(p->elem.word));
382         ui->DtBiao_tableWidget->setItem(i,1,new QTableWidgetItem(QString("%1").arg(p->elem.count)));
383         ui->DtBiao_tableWidget->setItem(i,2,new QTableWidgetItem(QString(" ( %1 , %2 )").arg(p->elem.row_head->row).arg(p->elem.row_head->page)));
384         all_count+=p->elem.count;//所有单词求和
385 
386         //如果当前单词出现次数比高频词汇数组的最后一个元素大,则进行插入
387         if(p->elem.count>high_word[HIGH_LENTH-1].count){
388             j=0;
389             while(j<HIGH_LENTH){
390                 if(p->elem.count>high_word[j].count){
391                     q=&high_word[j];
392                     for ( r = &high_word[HIGH_LENTH-1]; r >= q; r-- )   // 插入位置之后元素逐个右移
393                     {
394                         * ( r + 1 ) = *r;
395                     }
396                     high_word[j].count=p->elem.count;
397                     strcpy(high_word[j].word,p->elem.word);
398                     break;
399                 }
400                 j++;
401             }
402 
403         }
404 //        if(i<100){
405 //            QComboBox *comBox = new QComboBox();
406 //            while(p->elem.row_head!=p->elem.row_tail->next){
407 //                comBox->addItem(tr(" ( %1 , %2 )").arg(p->elem.row_head->row).arg(p->elem.row_head->page));
408 //                p->elem.row_head=p->elem.row_head->next;
409 //            }
410 //            ui->DtBiao_tableWidget->setCellWidget(i,2,comBox);
411 //        }
412         i++;
413         if (p->Rchild)
414              stack[++top] = p->Rchild;//右孩子进栈
415         if (p->Lchild)
416              stack[++top] = p->Lchild;//左孩子进栈
417     }
418     ui->DtBiao_tableWidget->setItem(0,5,new QTableWidgetItem(QString("总种类:%1").arg(i)));
419     ui->DtBiao_tableWidget->setItem(1,5,new QTableWidgetItem(QString("总单词:%1").arg(all_count)));
420 
421     i=0;
422     while(i<HIGH_LENTH){//高频词汇
423         if(high_word[i].count>1){
424             ui->DtBiao_tableWidget->setItem(i,3,new QTableWidgetItem(high_word[i].word));
425             ui->DtBiao_tableWidget->setItem(i,4,new QTableWidgetItem(QString("%1").arg(high_word[i].count)));
426         }
427        i++;
428         }
429 }
430 
431 /**********InOrder**********/
432 int frmMain::InOrderTraverse(DtList *T){
433     int i=0;
434 
435         if(T!=NULL){
436                 InOrderTraverse(T->Rchild);
437                 ui->DtBiao_tableWidget->insertRow(i);
438                 ui->DtBiao_tableWidget->setItem(i,0,new QTableWidgetItem(T->elem.word));
439                 ui->DtBiao_tableWidget->setItem(i,1,new QTableWidgetItem(QString("%1").arg(T->elem.count)));
440                 ui->DtBiao_tableWidget->setItem(i,2,new QTableWidgetItem(QString(" ( %1 , %2 )").arg(T->elem.row_head->row).arg(T->elem.row_head->page)));
441                 /*
442                 if(i<500){
443                     QComboBox *comBox = new QComboBox();
444                     while(T->elem.row_head){
445                         comBox->addItem(tr("%1").arg(T->elem.row_head->row));
446                         T->elem.row_head=T->elem.row_head->next;
447                     }
448                     ui->DtBiao_tableWidget->setCellWidget(i,2,comBox);
449                 }
450                 */
451                 InOrderTraverse(T->Lchild);
452                 return OK;
453         }
454         return FALSE;
455 }
456 
457 /************postOrder**************/
458 int frmMain::Dt_List_postOrder(DtList *T){
459     int i=0;
460         if (T != NULL) {
461                 Dt_List_postOrder(T->Lchild);
462                 Dt_List_postOrder(T->Rchild);
463                 ui->DtBiao_tableWidget->insertRow(i);
464                 ui->DtBiao_tableWidget->setItem(i,0,new QTableWidgetItem(T->elem.word));
465                 ui->DtBiao_tableWidget->setItem(i,1,new QTableWidgetItem(QString("%1").arg(T->elem.count)));
466                 ui->DtBiao_tableWidget->setItem(i,2,new QTableWidgetItem(QString(" ( %1 , %2 )").arg(T->elem.row_head->row).arg(T->elem.row_head->page)));
467 /*
468                 if(i<500){
469                     QComboBox *comBox = new QComboBox();
470                     while(T->elem.row_head){
471                         comBox->addItem(tr("%1").arg(T->elem.row_head->row));
472                         T->elem.row_head=T->elem.row_head->next;
473                     }
474                     ui->DtBiao_tableWidget->setCellWidget(i,2,comBox);
475                 }*/
476                 return OK;
477         }
478 return FALSE;
479 }

 

 

HASH表

 

  1 /******************************
  2 
  3           HASH表实现
  4 
  5   *******************************/
  6 
  7 
  8 /***哈希表遍历****/
  9 void frmMain::HASH_List_print(Hash_Header *L){
 10 
 11     long all_count=0;
 12     int i=0,j=0,HIGH_LENTH=100,w;
 13     Link_Node *p=NULL;
 14     High_count high_word[HIGH_LENTH],*r,*q;
 15 
 16     while(i<HIGH_LENTH){
 17         high_word[i].count=0;
 18         i++;
 19     }
 20 
 21     for(i=0;i<HASH_TABLE_LEN;i++){
 22         p=L[i].Link_head;//头指针
 23         while(p){/*当p不为空时*/
 24             ui->HASH_tableWidget->insertRow(j);//给表格添加新行
 25             ui->HASH_tableWidget->setItem(j,0,new QTableWidgetItem(p->word));
 26             ui->HASH_tableWidget->setItem(j,1,new QTableWidgetItem(QString("%1").arg(p->count)));
 27             ui->HASH_tableWidget->setItem(j,2,new QTableWidgetItem(QString(" ( %1 , %2 )").arg(p->row_head->row).arg(p->row_head->page)));
 28 
 29             all_count+=p->count;//所有单词求和
 30 
 31             //如果当前单词出现次数比高频词汇数组的最后一个元素大,则进行插入
 32             if(p->count>high_word[HIGH_LENTH-1].count){
 33                 w=0;
 34                 while(w<HIGH_LENTH){
 35                     if(p->count>high_word[w].count){
 36                         q=&high_word[w];
 37                         for ( r = &high_word[HIGH_LENTH-1]; r >= q; r-- )   // 插入位置之后元素逐个右移
 38                         {
 39                             * ( r + 1 ) = *r;
 40                         }
 41                         high_word[w].count=p->count;
 42                         strcpy(high_word[w].word,p->word);
 43                         break;
 44                     }
 45                     w++;
 46                 }
 47             }
 48 
 49 //            if(j<10){
 50 //                QComboBox *comBox = new QComboBox();
 51 //                while(p->row_head!=p->row_tail->next){
 52 //                    comBox->addItem(tr(" ( %1 , %2 )").arg(p->row_head->row).arg(p->row_head->page));
 53 //                    p->row_head=p->row_head->next;
 54 //                }
 55 //                ui->HASH_tableWidget->setCellWidget(j,2,comBox);
 56 //            }
 57 
 58             j++;//给表格添加新行
 59             p=p->next;
 60         }
 61     }
 62 
 63     ui->HASH_tableWidget->setItem(0,5,new QTableWidgetItem(QString("总种类:%1").arg(j)));
 64     ui->HASH_tableWidget->setItem(1,5,new QTableWidgetItem(QString("总单词:%1").arg(all_count)));
 65 
 66     i=0;
 67     while(i<HIGH_LENTH){
 68         if(high_word[i].count>1){
 69             ui->HASH_tableWidget->setItem(i,3,new QTableWidgetItem(high_word[i].word));
 70             ui->HASH_tableWidget->setItem(i,4,new QTableWidgetItem(QString("%1").arg(high_word[i].count)));
 71         }
 72        i++;
 73     }
 74 
 75 
 76 }
 77 
 78 /***计算哈希值***
 79 
 80   取单词的第一、二字符,把他们的ASCLL值求和并对表长取余
 81 
 82 ***************/
 83 int frmMain::HASH_func(char *word){
 84 
 85     int hash=0;
 86 
 87     if(strlen(word)==1){
 88         hash=word[0]%HASH_TABLE_LEN;
 89         return hash;
 90     }else{
 91         hash=(word[0]+word[1])%HASH_TABLE_LEN;
 92         return hash;
 93     }
 94 
 95 return -1;
 96 }
 97 
 98 /***搜索哈希值对应线性表***/
 99 int frmMain::hash_List_Search(Link_Node *L, char *fword, Link_Node **p){
100 
101     Link_Node *q=L;
102 
103     while(q){
104         if(strcmp(q->word,fword)==0){
105             *p=q;
106             return 1;//如果找到则返回
107         }
108         q=q->next;
109     }
110 return 0;
111 }
112 
113 /****哈希表插入****
114 
115   以后进先出的方式
116 
117 ****************/
118 int frmMain::hash_List_Insert(Link_Node **L, char *fword,int row){
119 
120     Link_Node *p=*L,*q;
121 
122     if((*L)==NULL){
123         *L=(Link_Node*)malloc(sizeof(Link_Node));
124         (*L)->count=1;
125         (*L)->next=NULL;
126         strcpy((*L)->word,fword);
127 
128         (*L)->row_head=(row_next*)malloc(sizeof(row_next));
129         (*L)->row_head->row=row%PAGE_LINE;
130         (*L)->row_head->page=row/PAGE_LINE+1;
131         (*L)->row_head->next=NULL;
132         (*L)->row_tail=(*L)->row_head;
133         return 1;
134     }else{
135 
136         q=(Link_Node*)malloc(sizeof(Link_Node));
137         q->count=1;
138 
139         q->row_head=(row_next*)malloc(sizeof(row_next));
140         q->row_head->row=row%PAGE_LINE;
141         q->row_head->page=row/PAGE_LINE+1;
142         q->row_head->next=NULL;
143         q->row_tail=q->row_head;
144 
145         q->next=(*L)->next;
146         strcpy(q->word,fword);
147         (*L)->next=q;
148         return 1;
149     }
150 
151 return 0;
152 
153 }
154 
155 int frmMain::on_Btn_HASH_start(){
156 
157     /*计算所消耗的时间---*/
158     DWORD start_create,     /*创建哈希表开始时间*/
159           stop_create,      /*创建哈希表结束时间*/
160           search_began_dt,  /*搜索开始时间*/
161           search_end_dt,    /*搜索结束时间*/
162           search_time_dt=0, /*搜索时间*/
163           Insert_began_dt,  /*插入开始时间*/
164           Insert_end_dt,    /*插入结束时间*/
165           Insert_time_dt=0, /*插入时间*/
166           search_all_time=0,/*搜索总时间*/
167           insert_all_time=0,/*插入总时间*/
168           order_began_hash, /*遍历开始时间*/
169           order_end_hash;   /*遍历结束时间*/
170 
171     start_create = GetTickCount();//创建哈希表开始计时
172 
173 
174     Hash_Header L[HASH_TABLE_LEN];//哈希表数组声明
175 
176     int i,j=0,pronum=0,y=0;
177 
178     /*哈希表数组初始化*/
179     for(i=0;i<HASH_TABLE_LEN;i++){
180         L[i].Link_head=NULL;
181     }
182 
183     /*清空表格内容*/
184     ui->HASH_tableWidget->clearContents();
185     for(j=ui->HASH_tableWidget->rowCount();j>=0;j--){
186 
187         ui->HASH_tableWidget->removeRow(j);
188     }
189 
190 
191     /*****进度条****/
192     for(y=0;y<=2;y++){
193         //ui->progressBar->setValue(pronum);
194         Sleep(1);
195         for(pronum=0;pronum<=75;pronum++){
196             ui->progressBar->setValue(pronum);
197             //Sleep(1);
198         }
199     }
200 
201 
202     FILE *f1;
203     FILE* fp=fopen("C:\Qt\src\QUI\linshi4.txt","wb");
204 
205     QString str=ui->HaSH_Plaintext->toPlainText();  //从plaintext中读取用户输入的数据
206     fprintf(fp,"%s",str.toStdString().c_str());     //把读取到的文本内容临时保存到text文件
207     fclose(fp); //关闭文件
208 
209     char fword[MAX_CHARACTER];          // 使用fword数组保存文件中的单词
210     fword[MAX_CHARACTER - 1] = '\0';    //字符串数组最后以'\0'结束
211     Link_Node *p = NULL;             // 设置p为在HASH 表中的位置
212     int hash_value=-1;              //hash_value 为对应单词哈希值
213     int row=1;
214     row_next *row_p;
215 
216 
217     f1=fopen("QtsrcQUIlinshi4.txt","r");
218 
219     if(f1==NULL) return 0;
220 
221     while ( !feof ( f1 ) )      // 读文件未结束
222     {
223 
224         int judge = pickword ( f1, fword ,&row); // 从f指向的文件中提取单词到fword中
225 
226         if ( -1 == judge )          // 数组越界时跳过该单词
227         {
228             continue;
229         }
230 
231         if ( -2 == judge ){
232             continue;
233         }
234 
235         hash_value=HASH_func(fword);   //计算哈希值
236 
237         //qDebug() << tr("hash_value:%1 ms").arg(hash_value);
238 
239         if(hash_value==-1)      /**无单词***/
240             return 0;
241 
242         search_began_dt=GetTickCount();/*搜索开始计时*/
243 
244         if ( hash_List_Search ( L[hash_value].Link_head, fword, &p ) )
245         {
246             search_end_dt=GetTickCount();/*搜索结束计时*/
247 
248             /*记录最长时间*/
249             if(search_time_dt<(search_end_dt-search_began_dt)){
250                 search_time_dt=search_end_dt-search_began_dt;
251             }
252             /*记录总时间*/
253             search_all_time=search_all_time+(search_end_dt-search_began_dt);
254 
255             // 在HASH表中找到该单词
256             p->count++;          // 单词出现次数加1
257 
258             row_p=(row_next*)malloc(sizeof(row_next));
259             row_p->row=row%PAGE_LINE;
260             row_p->page=row/PAGE_LINE+1;
261             p->row_tail->next=row_p;
262             p->row_tail=p->row_tail->next;
263         }
264         else
265         {
266             /*插入开始计时*/
267             Insert_began_dt=GetTickCount();
268 
269             // HASH表中未找到该单词
270             hash_List_Insert ( &(L[hash_value].Link_head),fword,row);      // 插入
271 
272             /*插入结束计时*/
273             Insert_end_dt=GetTickCount();
274 
275             /*记录最长时间*/
276             if(Insert_time_dt<(Insert_end_dt-Insert_began_dt)){
277                 Insert_time_dt=Insert_end_dt-Insert_began_dt;
278             }
279 
280             /*记录总时间*/
281             insert_all_time=insert_all_time+(Insert_end_dt-Insert_began_dt);
282         }
283 
284     }
285     fclose(f1);//关闭文件
286 
287     order_began_hash=GetTickCount();/*遍历开始计时*/
288 
289 //    j=0;
290 //    for(i=0;i<HASH_TABLE_LEN;i++){
291 //        p=L[i].Link_head;
292 //        while(p){
293 //            ui->HASH_tableWidget->insertRow(j);
294 //        ui->HASH_tableWidget->setItem(j,0,new QTableWidgetItem(p->word));
295 //ui->HASH_tableWidget->setItem(j,1,newQTableWidgetItem(QString("%1").arg(p->count)));
296 //ui->HASH_tableWidget->setItem(j,2,newQTableWidgetItem(QString("( %1 , %2 )").arg(p->row_head->row).arg(p->row_head->page)));
297 //            j++;
298 //            p=p->next;
299 //        }
300 //    }
301 
302     order_end_hash=GetTickCount();/*遍历结束计时*/
303 
304 
305     /*****进度条****/
306     for(y=0;y<=1;y++){
307         Sleep(1);
308         for(pronum=0;pronum<=100;pronum++){
309             ui->progressBar->setValue(pronum);
310             //Sleep(1);
311         }
312     }
313 
314     /****程序运行结束,计算时间并显示****/
315     stop_create = GetTickCount();
316     QString str1=tr("创建时间:%1 ms").arg(stop_create - start_create);
317     ui->HASH_TimeLine->setText(str1);
318     str1=tr("搜索:%1 ms,最长:%2 ms").arg(search_all_time).arg(search_time_dt);
319     ui->hash_search_ltimeline->setText(str1);
320     str1=tr("插入:%1 ms,最长:%2 ms").arg(insert_all_time).arg(Insert_time_dt);
321     ui->hash_insert_timeline->setText(str1);
322     str1=tr("遍历时间 : %1 ms").arg(order_end_hash-order_began_hash);
323     ui->hash_order_line->setText(str1);
324 
325     HASH_List_print(L);
326 /*
327     j=0;
328     for(i=0;i<HASH_TABLE_LEN;i++){
329         p=L[i].Link_head;
330         while(p){
331             QComboBox *comBox=new QComboBox;
332             while(p->row_head){
333                 comBox->addItem(tr("%1").arg(p->row_head->row));
334                 p->row_head=p->row_head->next;
335             }
336             ui->HASH_tableWidget->setCellWidget(j,2,comBox);
337             j++;
338             p=p->next;
339         }
340     }
341 */
342 }

 

 

以上是主要的功能源码,整体源码需要的请留言。

转载于:https://www.cnblogs.com/alimjan/p/9125919.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值