数据结构第四章总结

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

串的定义其实在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

输出样例:

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

6KMP算法的代码实现运用到此题
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,don‘t 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]!=‘\0‘){
        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] = ‘\0‘; //给t补上结尾符

        j=0;
    while(t[j]!=‘\0‘){//处理单独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]==‘\0‘)
        {//处理结尾剩余得一个空格
               ++j;
            continue;
        }   

        cout<<t[j++];
         }
         cout<<endl;
  }
bool isSeparator(char ch)
{  //判断ch是否分隔符
  //ch可能是:数字、字母、标点、空格、\0
  //分隔符:!(数字、小写字母、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算法的解析,看完之后其实也颇有收获的

原文地址:https://www.cnblogs.com/fengwanthousand/p/10708000.html

时间: 2024-10-05 11:28:39

数据结构第四章总结的相关文章

数据结构第四章小结

任选本章一道题目,谈谈你解决该题的心得体会.同时谈谈你对上次制定目标的完成情况, 以及接下来的目标. 一.第四章主要学习了串,我觉得最重要的两个内容,一个是AI核心代码,一个是稀疏矩阵的十字链表压缩存储:AI核心代码呢,老师在课堂上讲了一部分,自己也接受了挺多的,当天我就趁热打铁在通识课上回味了一下,老师有留给我们自己完成can you 的那一部分内容,之前有一部分是you变成I,我参照着之前的自己写了一遍,但是一开始出现了错误,又重新写了好几遍,但是总是会出现warning,可能是溢出的问题,

数据结构第四章学习小结

第四章主要是串和数组的学习,之前对串和数组的应用仅限于对其单独处理,本章学习着重于对具体题目的实际操作,实践了串的模式匹配算法,对其有了更深入的了解,数组的应用拓展到了稀疏矩阵的存储的实现. 一.串 串的模式匹配 BF算法 首先未匹配到串尾时,将两个字符串一一匹配,可用C++自带的length()函数实现 while(i<=S.length()&&j<=T.length()) 接下来就是匹配的过程 if(S[i]==T[j]){ i++;j++; }//若匹配则继续比较下一位

数据结构——第四章图:01图相关定义

1.图的定义:图是一种网状数据结构,形式化定义如下:图Graph = (V, R),V = {x | x ∈ DataObject},R = {VR},VR = {<x, y> | P(x, y) ∧ (x, y ∈ V)}.集合DataObject中的所有元素具有相同的特性.V中的数据元素通常为顶点(vertex),VR是两个顶点之间关系的集合,P(x, y)表示x和y之间有特定的关系属性P. (1)若<x, y> ∈ VR,则<x, y>表示从顶点x到顶点y的一条弧

C语言数据结构——第四章 串

四.串 4.1-串的基本概念 串的定义 串是由数字.字母或其他字符组成的有限序列,一般记为 StringName = “a[0]a[1]a[2]···a[i]···a[n-1]”(n>0,0<=i<=n-1) 其中StringName是串名,双引号内的序列是该串的值,n为串的长度,i为某一字符在该串中的下标 串的常用术语 串的长度:串中包含字符个数即为串的长度 空串:串中不包含任何字符时被称为空串,此时串的长度为0 空格串:由一个或多个空格组成的串被称为空格串,它的长度是串中空格的个数

《数据结构与算法分析:C语言描述》复习——第四章“树”——AVL树

2014.06.15 16:22 简介: AVL树是一种高度平衡的二叉搜索树,其命名源自于联合发明算法的三位科学家的名字的首字母.此处“平衡”的定义是:任意节点的左右子树的高度相差不超过1.有了这个平衡的性质,使得AVL树的高度H总是接近log(N),因此各种增删改查的操作的复杂度能够保证在对数级别.没有bad case是AVL树与普通的二叉搜索树的最大区别.为了实现平衡性质,我们需要记录每个节点的高度(或者平衡因子)来检测不平衡的情况.为了修正高度不平衡,需要用到“旋转”的方法,分为单旋转和双

算法导论笔记——第十二~十四章 数据结构(二)树

第十二章 二叉搜索树 >=左子树的所有key,<=右子树的所有key 在一棵高度为h的二叉搜索树上,动态集合上的操作SEARCH,MINIMUM,MAXIMUM,SUCCESSOR,PREDECESSOR,INSERT和DELETE可以在O(h)时间内完成. h>=(lgn向下取整) 和快速排序算法一样,其平均性能更接近于最好情形. 随机构建二叉搜索树期望高度为O(lgn). 各种操作请自行查阅. 第十三章 红黑树 是一种(近似)平衡的二叉搜索树.可以保证在最坏情况下基本动态集合操作的时

【数据结构】第四章学习小结

串.数组 在第四章中,我学到的主要是关于串与数组的内容,至于广义表,既然老师让我们课后有时间去看,那我这里就先不讲广义表了(其实只是粗略的看了一下,还没看懂) 在上学期的c++中我就已经学过有关串的一些知识,对于串还是可以很好的理解的,在数据结构中,串将被看作是一种特殊的线性表,跟线性表一样,串也有两种基本存储结构,个人觉得顺序存储结构对于串的运用比较方便,简单易懂,所以在作业题中会首先考虑使用顺序串. 串有许多很重要的应用,例如搜索引擎,数据压缩等,这些应用都离不开串的模式匹配算法(子串的定位

20145320《Java程序设计》第3周学习总结(第四章)

20145320<Java程序设计>第3周学习总结(第四章) 教材学习内容总结 对象(Object):存在的具体实体,具有明确的状态和行为 类(Class):具有相同属性和行为的一组对象的集合,用于组合各个对象所共有操作和属性的一种机制 从类看对象:类定义可以视为一个具有类似特性与共同行为的对象的模板,可用来产生对象 从对象看类:类的产生,是从少数实例,推广到大量相似实例的抽象化过程(abstraction) 类是对象的设计图,对象是类的实例,生成对象要先定义类 4.1 类与对象 定义类使用c

[现代操作系统笔记][第四章文件系统]

第四章 文件系统 4.1 文件 从用户角度来考察文件.用户如何使用文件,文件有那些特性. 4.1.1 文件命名 文件一种抽象机制,提供了一种在磁盘上保留信息而且以后方便读取的方法. 有的文件系统区分大小写,有的则不区分 Unix是前者,MS-DOS是后者 FAT-16,FAT-32,NTFS. FAT-16(File Allocation Table,文件配置表) : Windows 95 FAT-32 : Windows 98 NTFS(New Technology File System,新