【数据结构】英汉翻译小词典

一、实验题目及要求

题目:英汉翻译小词典

需求:

1、根据所提供的词典http://github.com/1eez/103976建立英文词典;

2、任意输入单词,判断该单词是否在词典中,输出查找结果,同时输入单词匹配过程中对比的中间关键字;

3、模仿Google的搜索界面,根据用户输入实时显示备选词。

二、概要设计

本次实验所用的数据结构为二叉搜索树BST,BST树具有以下特点:左子树上所有结点的值均小于或等于它的根结点的值;右子树上所有结点的值均大于或等于它的根结点的值;左、右子树也分别为二叉排序树。如果使用BST树将数据组织起来,树的每个结点都包含了健值 key、数据值 data、左子女指针、右子女指针。其中键值 key 是最核心的部分,它的值决定了树的组织形状;左子节点指针指向左子节点;右子节点指针指向右子节点;数据值 data 是该结点对应的数据,可以根据键值key找到数据data,因此适用于词典中单词的存储。

设计了两种建树的方法,分别为常规方法和折半方法;对BST树的操作有插入结点和搜索结点。使用Qt进行窗口交互设计,在widget.h中,widget实现的功能有读取csv文件、顺序方法搜索查找和BST搜索查找;用两个QStringList来分别存储英语单词和释义,方便QCompleter的使用,接收顺序输入序列时,采用折半思想,先问左侧数据,再访问右侧数据,以此递归。

由于英文词典中存在汉字字符,所以必须解决中文乱码问题。在使用 QTextStream 读写有中文内容的文本文件时,为了能正确识别 Unicode 码,需要调用 setAutoDetectUnicode(true),设置 QTextStream 可以自动识别 Unicode 码,如果不做此设置,读取文件的中文将是乱码,无法正常显示。为解决 Unicode 的识别问题,可以在应用程序中做全局的设置,使得应用程序支持 Unicode,方法是在 main() 函数中使用 QTextCodec 类进行编码设置。在本次实验中,在main()函数中添加语句
QTextCodec *codec=QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForLocale(codec);
这样就设置了应用程序使用的编码解码器,在应用程序内就有了对 Unicode 码的支持。在前面的 openTextByStream() 函数中,即使不用 setAutoDetectUnicode(true) 也可以正常显示汉字了。
三、详细设计
在BST结点类中定义了QString类型的data和BSTNode*类型的left和right,分别为左孩子指针和右孩子指针;在BST树类中定义了BSTNode类型的根节点root指针,并有Insert、Build1、Build2三个函数成员,分别执行插入节点、常规方法建树和折半方法建树操作。
struct BSTNode
{
    QString data;
    BSTNode *left,*right;
    //构造函数
    BSTNode():left(NULL),right(NULL){}
    BSTNode(QString str,BSTNode *l=NULL,BSTNode *r=NULL):data(str),left(l),right(r){}
    //析构函数
    ~BSTNode(){}
};

class BST
{
public:
    BSTNode *root;
    //构造和析构
    BST():root(NULL){}
    BST(BSTNode *r):root(r){}
    ~BST(){}
    bool Insert(QString str,BSTNode *&rootPtr);//插入结点
    bool Build1(QVector<QString> v);//常规方法建树
    bool Build2(QVector<QString> v);//折半方法建树
    BSTNode* Search(QString str,BSTNode *rootPtr,int &amount);//搜索结点
};
插入结点操作,如果rootPtr指针为空,就用new关键字动态分配内存空间;否则如果str小于rootPtr的data,就递归地调用Insert函数插入左子女,如果str大于rootPtr的data,就递归地调用Insert函数插入右子女。
bool BST::Insert(QString str,BSTNode *&rootPtr) 
{
    if(rootPtr==NULL)
    {
        rootPtr=new BSTNode(str);
        if(rootPtr==NULL)
            qDebug()<<"错误!";
        return true; 
    }
    else if(str<rootPtr->data)
        Insert(str,rootPtr->left);
    else if(str>rootPtr->data)
        Insert(str,rootPtr->right);
    else
        return false;//结点已存在
}

常规方法建立BST树,如果动态数组v的大小为0,返回false;否则采用for循环调用Insert函数依次插入每个结点。

bool BST::Build1(QVector<QString> v)
{
    if(v.size()==0)
        return false;
    for(int i=0;i<v.size();i++)
       Insert(v.at(i),root);
   return true;
}

折半方法建立BST树,设置变量mid值为v的大小的一半,分别在左侧和右侧序列进行插入。

bool BST::Build2(QVector<QString> v) 
{
    if (v.size() == 0)
        return false;
    int mid;
    mid = v.size() / 2;
    Insert(v[mid], root);
    QVector<QString> pre = v;
    for (int i = 0; i < v.size() - mid; i++)
    {
        QVector<QString>::iterator pEnd = pre.end();
        pre.erase(--pEnd);//折半左侧序列
    }
    Build2(pre);
    QVector<QString> post = v;
    for (int i = 0; i < mid + 1; i++)
    {
        QVector<QString>::iterator pBegin = post.begin();
        post.erase(pBegin);//折半右侧序列
    }
    Build2(post);
}

搜索结点操作,设置BSTNode*类型工作指针temp,初始值赋为rootPtr,在while循环中,用int类型的pos指示位置信息;在for循环中,如果出现temp->data.at(i)==' '就把i的值赋给pos,再定义字符串s,赋值为temp->data.mid(0, pos),将str与s进行比较,如果str较小,temp就指向左孩子,如果str较大,temp就指向右孩子,如果相等就返回temp,从而完成搜索结点操作。

BSTNode* BST::Search(QString str,BSTNode* rootPtr,int &amount)
{
    BSTNode* temp = new BSTNode;
    temp = rootPtr;
    while (temp != NULL)
    {
        int pos=0;
        for(int i=0;i<temp->data.size();i++)
        {
            if(temp->data.at(i)==' ')
            {
                pos=i;
                break;
            }
        }
        QString s = temp->data.mid(0, pos);
        qDebug()<<s;
        amount++;
        if (str < s)
            temp = temp->left;
        else if (str > s)
            temp = temp->right;
        else
            return temp;
    }
    return NULL;
}

ui界面已设置显示文本框read_only,按钮及文本框字体已设置;用两个QStringList来分别存储英语单词和释义,方便QCompleter的使用;在接收顺序输入序列时,先输入最中间数据,再访问左侧数据,再访问右侧数据,并以此递归。在widget.cpp中,先读取csv文件,之后实现搜索框下拉选项显示,之后把单词表和翻译表合并,方便BST搜索。
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{

    ui->setupUi(this);
    setFixedSize(420,680);
    ui->lineEdit->setPlaceholderText("Please enter:");//文本框提示

    //csv文件读取
    QStringList *word=new QStringList;
    QStringList *trans=new QStringList;
    ReadCsvFile(word,trans);

    //搜索框下拉选项实现
    QCompleter *MyInfor = new QCompleter(*word);
    MyInfor->setMaxVisibleItems(10);//设置下拉选项可见数量
    
ui->lineEdit->setCompleter(MyInfor);
QStringList *data=new QStringList;
    if(word->size()==trans->size())
    {
        for(int i=0;i<word->size();i++)
        {
            QString str;
            str=word->at(i)+' '+trans->at(i);
            data->push_back(str);
        }
    }

读取csv文件操作,QFile 类是Qt中进行文件读写操作的类,使用 QFile 可以直接打开或保存文本文件。QFile::open() 函数打开文件时需要传递 QIODevice::OpenModeFlag 枚举类型的参数,决定文件以什么方式打开,QIODevice::ReadOnly为以只读方式打开文件,用于载入文件。

void Widget::ReadCsvFile(QStringList *word,QStringList *trans)
{
    QFile inFile(":/data/EnWords.csv");
    QStringList lines; 
    if (inFile.open(QIODevice::ReadOnly))
    {
        QTextStream stream_text(&inFile);
        while (!stream_text.atEnd())
        {
            lines.push_back(stream_text.readLine());
        }
        for (int j = 0; j < lines.size(); j++)
        {
            QString line = lines.at(j);
            int pos=0;
            for(int i=0;i<line.size();i++)
            {
                if(line[i]==',')
                {
                    pos=i;
                    break;
                }
            }
            QString str1=line.mid(0,pos);
            QString str2=line.mid(pos+1,line.size()-pos-1);
            //去除引号
            str1.remove(0,1);
            str1.remove(str1.size()-1,1);
            word->push_back(str1);
            str2.remove(0,1);
            str2.remove(str2.size()-1,1);
            trans->push_back(str2);
        }
        inFile.close();
    }
}

顺序表查词操作,逐个检查关键字是否满足给定的条件。若查找到某个元素的关键字满足v[i].at(j)==' ',则查找成功,返回该元素在线性表中的位置。

QString Widget::SearchTrans1(QVector<QString>v,QString str)//顺序表搜索查词
{
    int amount=0;
    for(int i=0;i<v.size();i++)
    {
        int pos=0;
        for(int j=0;j<v[i].size();j++)
        {
            if(v[i].at(j)==' ')
            {
                pos=j;
                break;
            }
        }
        QString s = v[i].mid(0, pos);//分割字符串
        if(str==s)
        {
            amount=i+1;
            qDebug()<<"对比次数"<<amount;
            return v[i];
        }
    }
    return QString("0");
}

使用BST树查词操作,用bst对象调用Search函数,并设置了变量amount记录对比次数。

QString Widget::SearchTrans2(BST bst,QString str)//BST搜索查词
{
    BSTNode *bn=new BSTNode;
    int amount=0;
    bn=bst.Search(str,bst.root,amount);
    if(bn==NULL)
        return QString("0");
    else
    {
        qDebug()<<"对比次数为:"<<amount;
        return bn->data;
    }
}

四、测试结果

界面显示:

0c19e0c21c9244ce8747051c87a0e3c1.png

 下拉词汇显示:

a6cdb4e54ba34efbb654b6b9ae37daf7.png

查询结果:

5c95675a60344881b3b4346d487255e6.png 

 

五、源代码 

bst.cpp

#include "bst.h"
#include <QDebug>

bool BST::Insert(QString str,BSTNode *&rootPtr)//插入结点
{
    if(rootPtr==NULL)
    {
        rootPtr=new BSTNode(str);
        if(rootPtr==NULL)
            qDebug()<<"错误!";
        return true; 
    }
    else if(str<rootPtr->data)
        Insert(str,rootPtr->left);
    else if(str>rootPtr->data)
        Insert(str,rootPtr->right);
    else
        return false; 
}

bool BST::Build1(QVector<QString> v)//常规方法建树
{
    if(v.size()==0)
        return false;
    for(int i=0;i<v.size();i++)
       Insert(v.at(i),root);
   return true;
}

bool BST::Build2(QVector<QString> v)//折半建树
{
    if (v.size() == 0)
        return false;
    int mid;
    mid = v.size() / 2;
    Insert(v[mid], root);
    QVector<QString> pre = v;
    for (int i = 0; i < v.size() - mid; i++)
    {
        QVector<QString>::iterator pEnd = pre.end();
        pre.erase(--pEnd);//折半左侧序列
    }
    Build2(pre);
    QVector<QString> post = v;
    for (int i = 0; i < mid + 1; i++)
    {
        QVector<QString>::iterator pBegin = post.begin();
        post.erase(pBegin);//折半右侧序列
    }
    Build2(post);
}

BSTNode* BST::Search(QString str,BSTNode* rootPtr,int &amount)//搜索结点
{
    BSTNode* temp = new BSTNode;
    temp = rootPtr;
    while (temp != NULL)
    {
        int pos=0;
        for(int i=0;i<temp->data.size();i++)
        {
            if(temp->data.at(i)==' ')
            {
                pos=i;
                break;
            }
        }
        QString s = temp->data.mid(0, pos);
        qDebug()<<s;
        amount++;
        if (str < s)
            temp = temp->left;
        else if (str > s)
            temp = temp->right;
        else
            return temp;
    }
    return NULL;
}

bst.h

#ifndef BST_H
#define BST_H

#include <stdlib.h>
#include <QString>
#include <QVector>

struct BSTNode
{
    QString data;
    BSTNode *left,*right;
    //构造函数
    BSTNode():left(NULL),right(NULL){}
    BSTNode(QString str,BSTNode *l=NULL,BSTNode *r=NULL):data(str),left(l),right(r){}
    //析构函数
    ~BSTNode(){}
};

class BST
{
public:
    BSTNode *root;
    //构造和析构
    BST():root(NULL){}
    BST(BSTNode *r):root(r){}
    ~BST(){}
    bool Insert(QString str,BSTNode *&rootPtr);//插入结点
    bool Build1(QVector<QString> v);//常规方法建树
    bool Build2(QVector<QString> v);//折半方法建树
    BSTNode* Search(QString str,BSTNode *rootPtr,int &amount);//搜索结点
};

#endif // BST_H

main.cpp

#include "widget.h"
#include <QApplication>
#include <QTextCodec>

int main(int argc, char *argv[])
{
    QTextCodec *codec=QTextCodec::codecForName("UTF-8");//使用UTF8使中文正常显示
    QTextCodec::setCodecForLocale(codec);
    QApplication a(argc, argv);
    Widget w;
    w.setWindowTitle("Translate");
    w.show();

    return a.exec();
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{

    ui->setupUi(this);
    setFixedSize(420,680);
    ui->lineEdit->setPlaceholderText("Please enter:"); 

    //csv文件读取
    QStringList *word=new QStringList;
    QStringList *trans=new QStringList;
    ReadCsvFile(word,trans); 
    QCompleter *MyInfor = new QCompleter(*word);
    MyInfor->setMaxVisibleItems(10);//设置下拉选项可见数量
    ui->lineEdit->setCompleter(MyInfor);

    QStringList *data=new QStringList;
    if(word->size()==trans->size())
    {
        for(int i=0;i<word->size();i++)
        {
            QString str;
            str=word->at(i)+' '+trans->at(i);
            data->push_back(str);
        }
    }
    QVector<QString> v;
    for(int i=0;i<data->size();i++)
        v.push_back(data->at(i));
    BST bst;
    //bst.Build1(v);//常规BST建树
    bst.Build2(v);//折半建树

    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString desWord=ui->lineEdit->text();
        //BST查找方式
        //QString desTrans=SearchTrans2(bst,desWord);
        //顺序查找方式
        QString desTrans=SearchTrans1(v,desWord);
        if(desTrans=="0")
            ui->textEdit->setText("Not Found:(");
        else
            ui->textEdit->setText(desTrans);
    });
}

Widget::~Widget()
{
    delete ui;
}

void Widget::ReadCsvFile(QStringList *word,QStringList *trans)//读取csv文件
{
    QFile inFile(":/data/EnWords.csv");
    QStringList lines; 
    if (inFile.open(QIODevice::ReadOnly))
    {
        QTextStream stream_text(&inFile);
        while (!stream_text.atEnd())
        {
            lines.push_back(stream_text.readLine());
        }
        for (int j = 0; j < lines.size(); j++)
        {
            QString line = lines.at(j);//逐行取出
            //以逗号分割当前行
            int pos=0;//第一个逗号的位置
            for(int i=0;i<line.size();i++)
            {
                if(line[i]==',')
                {
                    pos=i;
                    break;
                }
            }
            QString str1=line.mid(0,pos);
            QString str2=line.mid(pos+1,line.size()-pos-1);
            //去除引号
            str1.remove(0,1);
            str1.remove(str1.size()-1,1);
            word->push_back(str1);
            str2.remove(0,1);
            str2.remove(str2.size()-1,1);
            trans->push_back(str2);
        }
        inFile.close();
    }
}

QString Widget::SearchTrans1(QVector<QString>v,QString str)//顺序表搜索查词
{
    int amount=0;
    for(int i=0;i<v.size();i++)
    {
        int pos=0;
        for(int j=0;j<v[i].size();j++)
        {
            if(v[i].at(j)==' ')
            {
                pos=j;
                break;
            }
        }
        QString s = v[i].mid(0, pos);//分割字符串
        if(str==s)
        {
            amount=i+1;
            qDebug()<<"对比次数"<<amount;
            return v[i];
        }
    }
    return QString("0");
}

QString Widget::SearchTrans2(BST bst,QString str)//BST搜索查词
{
    BSTNode *bn=new BSTNode;
    int amount=0;
    bn=bst.Search(str,bst.root,amount);
    if(bn==NULL)
        return QString("0");
    else
    {
        qDebug()<<"对比次数为:"<<amount;
        return bn->data;
    }
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QStringList>
#include <QString>
#include <QCompleter>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QVector>
#include "bst.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    void ReadCsvFile(QStringList *word,QStringList *trans);//读取csv文件
    QString SearchTrans1(QVector<QString>v,QString str);//顺序表搜索查词
    QString SearchTrans2(BST bst,QString str);//BST搜索查词

private:
    Ui::Widget *ui;
};
#endif 

 

  • 7
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
这里提供两种实现数据结构英汉翻译词典的方法: 方法一:哈希表和顺序查找 ```python # 定义一个字典,key为英文单词,value为中文翻译 dictionary = {'apple': '苹果', 'banana': '香蕉', 'cherry': '樱桃', 'orange': '橙子', 'pear': '梨子'} # 定义一个函数,用于查找单词 def search_word(word): count = 0 # 记录比较次数 if word in dictionary: count += 1 return dictionary[word], count else: count += 1 return '未找到该单词', count # 测试查找单词 result, count = search_word('apple') print(result, count) # 输出:苹果 1 # 定义一个函数,用于插入单词 def insert_word(word, translation): if word not in dictionary: dictionary[word] = translation return '插入成功' else: return '该单词已存在' # 测试插入单词 result = insert_word('grape', '葡萄') print(result) # 输出:插入成功 # 定义一个函数,用于删除单词 def delete_word(word): if word in dictionary: del dictionary[word] return '删除成功' else: return '该单词不存在' # 测试删除单词 result = delete_word('banana') print(result) # 输出:删除成功 ``` 方法二:PAT树 ```python # 定义一个节点类 class Node: def __init__(self, char): self.char = char # 节点存储的字符 self.value = None # 节点存储的值 self.children = {} # 子节点 # 定义一个PAT树类 class PATTree: def __init__(self): self.root = Node('') # 根节点 # 定义一个函数,用于查找单词 def search_word(self, word): count = 0 # 记录比较次数 node = self.root for char in word: count += 1 if char in node.children: node = node.children[char] else: return '未找到该单词', count if node.value: return node.value, count else: return '未找到该单词', count # 定义一个函数,用于插入单词 def insert_word(self, word, translation): node = self.root for char in word: if char in node.children: node = node.children[char] else: new_node = Node(char) node.children[char] = new_node node = new_node node.value = translation # 定义一个函数,用于删除单词 def delete_word(self, word): node = self.root for char in word: if char in node.children: node = node.children[char] else: return '该单词不存在' if node.value: node.value = None return '删除成功' else: return '该单词不存在' # 测试PAT树 tree = PATTree() tree.insert_word('apple', '苹果') tree.insert_word('banana', '香蕉') tree.insert_word('cherry', '樱桃') result, count = tree.search_word('apple') print(result, count) # 输出:苹果 5 result = tree.delete_word('banana') print(result) # 输出:删除成功 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WiIsonEdwards

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值