《数据结构-用C语言描述第三版》课后答案 第四章

如有问题,欢迎评论区指正,因为时间和精力问题,部分题只给出思路,后续有时间会逐步完善,写不完,根本写不完啊,不然更新太慢了

1.简述下列术语:

(1)空串和空格串。

空串是长度为零的串,空格串是所有元素为空格的串

(2)串变量和串常量。

串变量是程序中用于存储字符串的变量,随着程序的运行,变量值可以改变

串常量是一个固定的字符串值

(3)主串和子串。

主串:包含子串的串称为主串

子串:主串中任意连续的子序列

(4)串变量的名字和串变量的值。

串变量的名字即变量名,串变量的值即变量存储的串值

2.选择题:

(1)函数 substr (" DATASTRUCTURE ",5,9)的返回值为(A).

A ." STRUCTURE "

B ." DATA "

C ." ASTRUCTUR "

D ." DATASTRUCTURE "

substr (str,pos,len)返回串str中pos位置其长度为len的子串

(2)下面关于串的叙述中,不正确的是(B)。

A .串是字符的有限序列

B .空串是由空格构成的串

C .模式匹配是串的一种重要运算

D .串既可以采用顺序存储,也可以采用链式存储

(3) StrCompare (' Computer ',' Compare ')的返回值是()。

A .-1
B .0
C .1
D .100

StrCompare(str1,str2);

依据字典序比较str1与str2

  1. str1 = str2 返回0
  2. 第一个不相等的字符 str1.i > str2.i 则返回1
  3. 第一个不相等的字符 str1.i < str2.i 则返回1

3.编写算法,实现顺序串的基本操作 StrReplace ( S , T , V )。

StrReplace(S,T,V);

串 S,T,V存在,使用V替换S中所有不重叠的T子串

答:

在顺序串的求子串、替换的基础上操作S串即可

4.假设以单链表结构表示串,每个结点数据域存放一个字符,且附设头结点。试编写算法,实现串的下列操作:

  1. StrAssign ( S , chars ); //生成一个值为chars的串
  2. StrCopy ( S , T );  //将串T复制到S
  3. StrCompare ( S , T );//比较串 S和T
  4. StrLength ( S );//返回串S的长度
  5. StrCat ( S , T );//将串T连接到S的后面
  6. SubString ( Sub , S , pos , len )。//返回pos位置起长度为len的子串
#include <stdio.h>

//定义链式存储的串节点
typedef struct SNode{
        char data;
        struct SNode *next;
}LinkString;

void StrAssign(LinkString *S, char chars[],int n){
        //初始化头结点
        S = (LinkString *)malloc(sizeof(struct SNode));
        S->next = NULL:
        struct Snode * t = S;
        struct SNode * p;
        for(int i=0;i<n;i++){
                p = (LinkString *)malloc(sizeof(struct SNode));
                p->data = chars[i];
                p->next = t->next;
                t->next = p;
                t = p;
        }
}

void StrCopy(LinkString *S, LinkString *T){
    /*
    需要考虑原先S和T长度问题
    S的长度大于T ,则逐个复制之后需要释放S多余的结点
    S的长度小于T , 则逐个复制之后还需要新建结点
    S的长度等于T ,则逐个复制即可
    */
    struct SNode *p = S;
    struct SNode *t = T;    
    while(p->next && t->next){
        p->next->data = t->next->data;
        p = p->next;
        t = t->next;
    }
    while(p->next!=NULL){
        struct SNode *temp = p->next;
        p->next = temp->next;
        free(temp);
    }
    while(t->next!=NULL){
        struct SNode *temp = (LinkString*)malloc(sizeof(struct SNode));
        temp->data = t->next->data;
        temp->next = p->next;
        p->next = temp;
        t = t->next;
    }
    
}

int StrCompare(LinkString *S,LinkString *T){
        struct SNode *p1 = S->next;
        struct SNode *p2 = T->next;
        while(p1 && p2){
                if(p1->data == p2->data){
                        p1 = p1->next;
                        p2 = p2->next;
                }else if(p1->data > p2->data){
                        return 1;
                }else {
                        return -1;
                }
        }
        if(p1){
                return 1;
        }
        if(p2){
                return -1;
        }
        return 0;
}

int StrLength(LinkString *S){
        struct SNode *p = S->next;
        int ret = 0;
        while(p){
                ret++;
                p = p->next;
        }
        return ret;
}


void StrCat(LinkString *S,LinkString *T){
        //将T附加到S的后面
        struct SNode *p = S->next;
        struct SNode *t = T->next;

        while(p->next){
                p = p->next;
        }

        while(t){
                struct SNode *temp = (LinkString *)malloc(sizeof(struct SNode));
                temp->data = t->data;
                temp->next = p->next;
                p->next = temp;
                t = t->next;
        }
}

LinkString *SubString(LinkString *S,int pos,int len){
        LinkString * ret = (LinkString *)malloc(sizeof(struct SNode));
        ret->next = NULL;
        struct SNode *p = ret;
        struct SNode *t = S->next;
        while(pos--){
                t = t->next;
        }
        while(len--){
                struct SNode *temp = (LinkString *)malloc(sizeof(struct SNode));
                temp->data = t->data;
                temp->next = p->next;
                p->next = temp;
                p = temp;
                t = t->next;
        }

        return ret;

}

5.已知: S =( xyz )*, T =( x + z )* y 。试利用连接、求子串和置换等操作,将 S 转换为 T 。

答:将S中的y替换为+,并在S后面连接y即可转换为T

6. S 和 T 是用结点大小为1的单链表存储的两个串,设计一个算法,将串 S 中首次与 T 匹配的子串逆置。

答:

首先找到串S中首次与T匹配的子串的位置

其次遍历链表并逆置链表

需要三个指针 prev(上个结点的指针) current(当前结点指针) next(下一个结点的指针)

记录并暂存起始指针位置

next = current->next

current->nexxxt  = prev

prev = current

current = next

即将current结点的next指针指向前面结点,同时记录原来顺序的next和prev

7.S 是用结点大小为4的单链表存储的串,分别编写算法,实现在第 k 个字符后插入串 T ,并从第 k 个字符删除 len 个字符。

答:

遍历链表串 找到第k个字符所在的结点indexk

两种思路

  • 当前结点记录有一个指示结点有效字符的变量,因此只需要将串T插入到indexk后面,改变indexk结点的有效字符数,将多余字符复制到结尾
  • 不牺牲indexk结点的空间,将T中字符一个个添加到第k个字符的后面,并将原来第k个字符后面的字符后移。此时需要暂存当前结点,将串T链接到后面后再逐个排序

8.编写算法,实现定长顺序串的如下操作:

1)将串 r 中所有值为ch1的字符换成ch2。

2)将串r中所有字符按照相反的次序仍存放在r中。

3)从串 r 中删除其值等于 ch 的所有字符。

4)从串r1中第 index 个字符起,求出首次与串r2相同的子串的起始位置。

5)从串 r 中删除所有与串r1相同的子串。

答:

(1)遍历字符串替换即可

(2)对于定长顺序串,逆置串只需要从首尾向中间交换字符值即可

(3)使用双指针,一个指针用于遍历,一个指针用于指示删除字符后后面的字符应该迁移的位置

(4)使用Brute-Force算法或者KMP算法均可

(5)在第四步的基础上将后面串前移即可

9.编写一个函数,将顺序串s1中的第 i 个字符到第 j 个字符之间的字符用串s2替换。

答:要考虑S1_{i-j}的长度和S2的长度大小

如果长度相等 则直接逐个替换即可

如果前者大于后者 则逐个替换之后还需要将后面的字符前移

如果后者大于前者 则在替换之前需要将后面的字符后移

10.编写算法,实现顺序串的基本操作 StrCompare ( s , t )。

答:假设顺序串的定义如下

#define MaxSize 1000
typedef struct SString{
    char data[1000];
    int length;
}SString;
void StrCompare(SString *S, SString *T){
    int i = 0;
    int j = 0;
    while(i < S->length && j < T->length){
        if(S->data[i] == T->data[j]){
            i++;
            j++;
        }else if(s->data[i] > s->data [j]){
            return 1;
        }else {
            return -1;
        }
    }
    if( i < S->length){
        return 1;
    }
    if(j < S->length){
        return -1;
    }
    return 0;
}

11.编写算法,实现顺序串的基本操作 StrReplace (& s , t , v )。

答:思路同前面顺序串的子串替换

12.令主串 S =' aaabbbababaabb ',子串='abaa',试分别用 Brute - Force 算法和 KMP 算法给出其匹配过程,并讨论模式匹配的匹配效率。

答:

Brute-Force算法

每次不匹配时,指向S的指针回溯至上次起始位置的下一个位置,指向子串的指针返回开始,因此,使用Brute-Force算法时,在第九次匹配时才会匹配成功

KMP算法

设i指向主串S的下标 j指向子串T的下标 下标从0开始

首先计算子串“abaa”的next数组 【0,0,0,1】,此时从下标0开始,很多地方下标是从1开始的,若从1开始,则next数组为【0,1,1,2】

第一次 S[0:4] = ‘aaab’ 第二个字符匹配不成功 则进入第二次匹配 此时i = 1 j =0 

第二次 S[1:5] = ‘aabb’ 第二个字符匹配不成功 则进入第三次匹配 此时i = 2 j =0

第三次 S[2,6] = 'abbb' 第三个字符匹配不成功 则进入第四次匹配 此时i = 4 j =0

第四次 S[4,9] = 'bbab' 第一个字符匹配不成功 则进入第四次匹配 此时i = 5 j =0

第五次 S[5,10] = 'baba' 第一个字符匹配不成功 则进入第四次匹配 此时i = 6 j =0

第六次 S[6,11] = 'abab' 第四个字符匹配不成功 则进入第四次匹配 此时i = 8 j =1

第七次 S[8,13] = 'abaa' 匹配成功

13.假设以顺序存储结构表示串,试设计一个算法,求串 S 和串 T 的一个最长公共子串,并分析算法的时间复杂度。

答:使用动态规划的思想解决问题

1.创建一个二位数组dp, 其中dp[i][j]表示以S[i] 和T[j]结尾的最长公共子串的长度

2.初始化dp[i][j], 如果S[i] = T[j] 则dp[i][j] = 1 否则等于0

3.遍历串S和T,进行状态转移如果s[i] = T[j], 则dp[i][j] = dp[i-1][j-1] +1 否则为0

4.状态转移过程中记录最大值以及i,j值

#include <stdio.h>

#define MaxSize 100
typedef struct SString{
	int length;
	char data[MaxSize];
}SString;

void getMax(SString *S,SString *T){
    int dp[S->length][T->length];
    int max = 0;
    int indexi;
    int indexj; 
    //初始化
    for(int i = 0;i<S->length;i++ ){
        for(int j = 0;j<T->length;j++){
            if(S->data[i] == T->data[j]){
                dp[i][j] = 1;
            }else{
                dp[i][j] = 0;
            }
        }
    }
    for(int i=0;i<S->length;i++){
	for(int j=0;j<T->length;j++){
		printf("%d\t",dp[i][j]);
	}
	printf("\n");
    }
    max = dp[0][0];
    indexi = 0;
    indexj = 0;
    //状态转移
    for(int i = 1;i<S->length;i++){
        for(int j = 1;j<T->length;j++){
            if(S->data[i] == T->data[j]){
                dp[i][j] = dp[i-1][j-1] +1;
            }else{
                dp[i][j] = 0;
            }
	    if(max<dp[i][j]){
		max = dp[i][j];
		indexi = i;
		indexj = j;
	    }
        }
    }
    for(int i=0;i<S->length;i++){
	for(int j=0;j<T->length;j++){
		printf("%d\t",dp[i][j]);
	}
	printf("\n");
    }

    printf("max = %d , indexi = %d , indexj = %d",max,indexi,indexj);
}

int main(){
	SString S;
	SString T;
	char a[10] = "aabababbab";
	char b[5]  = "ababc";
	S.length = 10;
	T.length = 5;
        for(int i=0;i<10;i++){
		S.data[i] = a[i];
	}	
	for(int i=0;i<5;i++){
		T.data[i] = b[i];
	}
	getMax(&S,&T);
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

惜日短

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

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

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

打赏作者

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

抵扣说明:

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

余额充值