数据结构第四章总结

Posted fengwanthousand

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构第四章总结相关的知识,希望对你有一定的参考价值。

数据结构第四章学习的是串,数组和广义表(广义表课程中没讲,问题不大)

串的定义其实在c++学习中就有所接触,所以这里不详说,  重点说的是两个串模式匹配算法

1.BF算法

BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;

若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。

2.KMP算法

KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。

具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

应用到PTA上的是

7-1 串的模式匹配 (30 分)
 

给定一个主串S(长度<=10^6)和一个模式T(长度<=10^5),要求在主串S中找出与模式T相匹配的子串,返回相匹配的子串中的第一个字符在主串S中出现的位置。

输入格式:

输入有两行: 第一行是主串S; 第二行是模式T.

输出格式:

输出相匹配的子串中的第一个字符在主串S中出现的位置。若匹配失败,输出0.

输入样例:

在这里给出一组输入。例如:

aaaaaba
ba

输出样例:

在这里给出相应的输出。例如:

6
KMP算法的代码实现运用到此题
int Index_KMP(SString S, SString T, int next[]) { //S主串,T模式串
    int i = 1, j = 1;       //i指主串,j指模式串
    int result = 0;
    while (i <= S.length&&j <= T.length) {
        if (j == 0 || S.ch[i] == T.ch[j]) {     /如果匹配接着往下比较,不匹配就右移T
            i++;
            j++;
        }
        else {
            j = next[j];
        }
    }
    if (j > T.length) {     //当j到最后仍与主串相等+1时匹配成功
        result = i - T.length;
    }
    return result;
}

主要还是getnext函数

void getNext(SString T, int next[]) {
    int i = 1, j = 0;   
    next[1] = 0;
    while (i < T.length) {
        if (j == 0 || T.ch[i] == T.ch[j]) { 
            i++;
            j++;
            if (T.ch[i] != T.ch[j]) {   //i和j都右移后如果不同,把最长串最后一个的位置给next
                next[i] = j;
            }
            else {          //但是如果相同,就让next变为next[j]        
                next[i] = next[j];
            }
        }
        else {              //如果j不为0且ch[i] 与 ch[j]不等,表示之前有相同串,但右移后又不同了  
            j = next[j];
        }
    }
  
}

 

最后则是学习到特殊矩阵的压缩存储

运用到例题有

7-1 稀疏矩阵 (30 分)
 

如果一个矩阵中,0元素占据了矩阵的大部分,那么这个矩阵称为“稀疏矩阵”。对于稀疏矩阵,传统的二维数组存储方式,会使用大量的内存来存储0,从而浪费大量内存。为此,可以用三元组的方式来存放一个稀疏矩阵。

对于一个给定的稀疏矩阵,设第r行、第c列值为v,且v不等于0,则这个值可以表示为 <。这个表示方法就称为三元组。那么,对于一个包含N个非零元素的稀疏矩阵,就可以用一个由N个三元组组成的表来存储了。

如:{<1, 1, 9>, <2, 3, 5>, <10, 20, 3>}就表示这样一个矩阵A:A[1,1]=9,A[2,3]=5,A[10,20]=3。其余元素为0。

要求查找某个非零数据是否在稀疏矩阵中,如果存在则输出其所在的行列号,不存在则输出ERROR。

输入格式:

共有N+2行输入: 第一行是三个整数m, n, N(N<=500),分别表示稀疏矩阵的行数、列数和矩阵中非零元素的个数,数据之间用空格间隔; 随后N行,输入稀疏矩阵的非零元素所在的行、列号和非零元素的值; 最后一行输入要查询的非0数据k。

输出格式:

如果存在则输出其行列号,不存在则输出ERROR。

输入样例:

在这里给出一组输入。例如:

10 29 3
2 18 -10
7 1 98
8 10 2
2

输出样例:

在这里给出相应的输出。例如:

8 10
代码如下:
#include<iostream>
using namespace std; 

typedef struct
{
    int i;//第i行
    int j;//第j行
    int v;//第i行第j列的值 
}Mnode;

typedef struct
{
    Mnode a[520];
    int length;//矩阵中非零元素的个数
     
}Tuple;

int main()
{
    Tuple T;
    
    int m,n,N;//m,矩阵行数,n,矩阵列数,N,矩阵的非零元素个数 
    cin>>m>>n>>N;
    
    T.length=N;

    for(int i=0;i<T.length;i++)
    {
        cin>>T.a[i].i;    //输入非零元素所在行,列号和非零元素的值 
        cin>>T.a[i].j;
        cin>>T.a[i].v;    
    } 
         
    int d; 
    cin>>d;//输入查询数据
    
    if(d!=0)
    {
        for(int i=0;i<T.length;i++)
    {
        if(T.a[i].v == d)
        {
            cout<<T.a[i].i<<" ";
            cout<<T.a[i].j;
        }
        
        if( (T.a[i].v != d) && (i == T.length-1))
            cout<<"ERROR";
        
        else i++;
    
    }
    }

 } 

收获:

本章内容较多,尤其是学习到两个新接触的算法,KMP算法带来的新思想对理解能力是一个挑战,

还有的是老师上课时带我们一步步去完成AI核心代码这道实践题,一步一步的编程思路可谓将问题

需要注意的细节都能展现在代码上,滴水不漏。也是一个编程基本功的体现,下来之后又重新按照老师的

算法思路一步步去完成,并加上老师还没讲到的can you 的改写,实现的代码:

7-2 AI核心代码 (30 分)
本题要求你实现一个简易版的 AI 英文问答程序,规则是:

无论用户说什么,首先把对方说的话在一行中原样打印出来;
消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
把原文中所有大写英文字母变成小写,除了 I;
把原文中所有独立的 I 和 me 换成 you;
把原文中所有的问号 ? 换成惊叹号 !;
把原文中所有独立的 can you 换成 I can —— 这里“独立”是指被空格或标点符号分隔开的单词;
在一行中输出替换后的句子作为 AI 的回答。
输入格式:
输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。

输出格式:
按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。
输入样例:
在这里给出一组输入。例如:

6
Hello ?
 Good to chat   with you
can   you speak Chinese?
Really?
Could you show me 5
What Is this prime? I,don t know
输出样例:
在这里给出相应的输出。例如:

Hello ?
AI: hello!
 Good to chat   with you
AI: good to chat with you
can   you speak Chinese?
AI: I can speak chinese!
Really?
AI: really!
Could you show me 5
AI: could you show you 5
What Is this prime? I,don t know
AI: what Is this prime! you,dont know



#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
string s;
 void go(string s);
 bool isSeparator(char ch);
 bool isPunctuation(char eh);
 bool iscanyou(char t[],int j) ;
int main()
{
    string s;
    int n, i;
    cin >> n;
    getchar(); //吸收回车符 
    for(i=1; i<=n; ++i){
        getline(cin, s);
        cout << s << endl;
        cout << "AI: ";
        go(s);//AI根据s输出对话    
    }
    return 0;
}

void go(string s)
{
    char t[3004];//输入全部是I的时候,输出长度是输入的三倍
    //string t;  

    int i, j;//i,j分别为s,t的下标
    
    //i定位到s的第一个非空字符 
    for(i=0; s[i]== ; ++i);//循环体为空

    j = 0;     //j的初值为0
    
    //从s的第一个非空字符开始,逐个扫描,分情况复制到t
    while(s[i]!=){
        if(s[i]==  && s[i-1]== ){
            ++i; //如果漏了这句,有连续空格时会死循环
            continue;
        }            
        if(s[i]==?){
            t[j++] = !;
            ++i;
            continue;
        }
        if(s[i]!=I){
            t[j++] = tolower(s[i++]);
            continue;
        }
        t[j++] = s[i++]; //s[i]=‘I‘的情况 
     }  
     
     t[j] = ; //给t补上结尾符
        
        j=0;
    while(t[j]!=){//处理单独I变成you,最主要还是isSeparator函数的编写 
         if(t[j]==I && (j==0 || isSeparator(t[j-1])) && isSeparator(t[j+1])){
             cout << "you";
             ++j;
             continue;
         }
         //同理,me与I一样做法 
         if(t[j]==m && t[j+1]==e && (j==0 || isSeparator(t[j-1])) && isSeparator(t[j+2])){
             cout << "you";
             j += 2;
             continue;
         }
         if(t[j]==  && isPunctuation(t[j+1])){//空格的下一个是标点,不输出 
           
             ++j;
            continue;
 } 
         if(iscanyou(t,j))
         {
             cout<<"I can";
             j+=7;
             continue;
         }
         
         if(s[j]== &&s[j+1]==)
        {//处理结尾剩余得一个空格
               ++j;
            continue;
        }   
        
        cout<<t[j++]; 
         } 
         cout<<endl;
  }     
bool isSeparator(char ch)
{  //判断ch是否分隔符 
  //ch可能是:数字、字母、标点、空格、
  //分隔符:!(数字、小写字母、I)
     ch = tolower(ch); 
     if(ch>=0 && ch<=9 || ch>=a && ch<=z || ch==I)
        return false;
     else 
        return true;    
}
bool isPunctuation(char eh)
{//判断空格下一个是标点,不输出

    eh=tolower(eh);
    if(eh>=0&&eh<=9||eh>=a&&eh<=z|| eh==I || eh== )
        return false;
    else
        return true;

} 
bool iscanyou(char t[],int j)
{ //处理can you的函数 
    if(t[j]==c&&t[j+1]==a&&t[j+2]==n&&t[j+3]== &&t[j+4]==y&&t[j+5]==o&&t[j+6]==u)
    {
        if((j==0||isSeparator(t[j-1]) )&&isSeparator(t[j+7]))
            return true; 
    } 
    else    
      return false;
            
}    
         
     

自己的编程能力有了一定的提高,但还要继续努力,达到自己理想中的状态。

 

希望自己能多点实践上机,好好巩固一下第四章学到的东西,而第五章将要学的树和二叉树

也要努力地跟上呀!

最后还是推荐一下学者网上老师发布的KMP算法的解析,看完之后其实也颇有收获的

 

 

以上是关于数据结构第四章总结的主要内容,如果未能解决你的问题,请参考以下文章

第四次实验总结

第四章的代码和总结

OO第四单元暨课程总结

OOP第四次到第六次作业总结

python常用代码片段总结

第四章总结