CH4-串、数组和广义表
目录
4.1 串的定义




4.2 案例引入


4.3 串的类型定义、存储结构及运算



4.3.1 顺序串
#define MAXLEN 255
typedef struct{
char ch[MAXLEN+1]; //存储串的一维数组
int length; //串的当前长度长度
}SString;
4.3.2 链串

#define CHUNKSIZE 80 //块的大小可由用户定义
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef struct{
Chunk *head,*tail; //串的头指针和尾指针
int curlen; //串的当前长度
}LString; //字符串的块链结构
4.3.3模式匹配算法

BF算法





#include "stdio.h"
#include "string.h"
#define MAXLEN 255
typedef struct{
char ch[MAXLEN+1]; //存储串的一维数组
int length; //串的当前长度长度
}SString;
int Index_BF(SString S, SString T, int pos);
int main()
{
SString S,T; int pos,flag;
printf("请输入主串:\n");
scanf("%s",&S.ch);
S.length=strlen(S.ch);
printf("请输入子串:\n");
scanf("%s",&T.ch);
T.length=strlen(T.ch);
printf("请输入主串起始查找下标pos (默认从0开始):\n");
scanf("%d",&pos);
flag=Index_BF(S,T,pos);
if (flag!=0)
printf("子串在主串的第%d个字符处\n",flag);
else
printf("子串不在主串中!\n");
return 0;
}
int Index_BF(SString S, SString T, int pos ){//主串S,子串T, 主串第pos个字符
int i=pos, j=1;
while (i<=S.length && j<=T.length) {
if (S.ch[i]==T.ch[j-1])
{++i; ++j; } //主串和子串依次匹配下一个字符
else
{i=i-j+2; j=1;}//主串、子串指针回溯重新开始下一次匹配
}
if (j>=T.length)
return i-T.length+1 ;//返回匹配的第一个字符的下标
else
return 0; //模式匹配不成功
}


KMP算法




void get_next(SString T, int &next[]){
i= 1; next[1] = 0; j = 0;
while( i<T.length){
if(j==O || T.ch[i]== T.ch[j]){
++i; ++j;
next[i] = j;
}
else
j = next[j];
}
int Index_KMP (SString S,SString T, int pos){
i= pos,j =1;
while (i<S.length && j<T.length) {
if (j==O || S.ch[i]==T.ch[j])
{ i++; j++; }
else
j=next[j]; //i不变,j后退
}
if (j>T.length)
return i-T.length+1; /*匹配成功*/
else
return O; /*返回不匹配标志*/
}



void get_nextval(SString T, int &nextval[]){
i= 1; nextval[1] = 0; j = 0;
while( i<T.length){
if(j==0 || T.ch[i]== T.ch[j]){
++i; ++j;
if(T.ch[i] != T.ch[j])
nextval[i] = j;
else
nextval[i] = nextval[j];
}
else j = nextval[j];
}
}
4.4 数组




4.4.1抽象数据类型定义



typedef struct {
ElemType* base; //数组元素基址(数组基址)
int dim; //数组维数
int* bounds; //数组维界基址(存放各位长度信息)
int* constants; //数组映象函数常量基址
}Array;
初始化
//创建多维数组
Status InitArray(Array *A,int dim,...) /*构造数组A,...代表各维下标值,是不确定的*/
{
int elemtotal=1,i; /*elemtotal是元素个数的总值*/
va_list ap; /*ap是定义的宏类型的变量,它是一个指向第一个参数地址的指针*/
if(dim<1||dim>MAX_ARRAY_DIM) /*判断维界是否合法*/
return ERROR;
(*A).dim=dim;
(*A).bounds=(int *)malloc(dim*sizeof(int));
if(!(*A).bounds) /*分配存储失败*/
exit(OVERFLOW);
va_start(ap,dim); /*初始化宏*/
for(i=0;i<dim;i++)
{
(*A).bounds[i]=va_arg(ap,int); /*取出其值*/
if((*A).bounds[i]<0) /*如果维界不合法,则退出*/
return UNDERFLOW; /*在math.h中定义为4*/
elemtotal*=(*A).bounds[i]; /*元素总数等于各维界的乘积*/
}
va_end(ap);
(*A).base=(ElemType *)malloc(elemtotal*sizeof(ElemType));
if(!(*A).base) /*分配存储失败*/
exit(OVERFLOW);
(*A).constants=(int *)malloc(dim*sizeof(int));
if(!(*A).constants) /*分配存储失败*/
exit(OVERFLOW);
(*A).constants[dim-1]=1;
for(i=dim-2;i>=0;i--)
(*A).constants[i]=(*A).bounds[i+1]*(*A).constants[i+1];
return OK;
}
销毁
Status DestroyArray(Array *A)
{
if((*A).base)
{
free((*A).base);
(*A).base=NULL;
}
else
return ERROR;
if((*A).bounds)
{
free((*A).bounds);
(*A).bounds=NULL;
}
else
return ERROR;
if((*A).constants)
{
free((*A).constants);
(*A).constants=NULL;
}
else
return ERROR;
return OK;
}
定位
//数组的定位
Status Locate(Array A,va_list ap,int *off)
{
int i,ind;
*off=0;
for(i=0;i<A.dim;i++)
{
ind=va_arg(ap,int);
if(ind<0||ind>=A.bounds[i])
return OVERFLOW;
*off+=A.constants[i]*ind; /*当你编译执行后看到结果就好理解了*/
}
return OK;
}
取值
Status Value(ElemType *e,Array A,...)
{
va_list ap;
Status result;
int off;
va_start(ap,A);
if((result=Locate(A,ap,&off)==OVERFLOW))
return result;
*e=*(A.base+off);
return OK;
}
赋值
//数组赋值
Status Assign(Array *A,ElemType e,...)
{
va_list ap;
Status result;
int off;
va_start(ap,e);
if((result=Locate(*A,ap,&off)==OVERFLOW))
return result;
*((*A).base+off)=e;
return OK;
}
测试
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "stdarg.h" /*通过宏来实现可变参数的问题*/
#define OK 1 /*宏定义结果状态代码*/
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_ARRAY_DIM 8
typedef int ElemType;
typedef int Status; /*Status是函数的类型,其值是结果状态代码*/
typedef struct{
ElemType *base; /*数组元素基址,用于将多维数组的值以一维方式输出*/
int dim; /*多维数组的维数*/
int *bounds; /*数组维界基址,用于输出各维下标值*/
int *constants; /*数组映像函数常量基址*/
}Array;
/*顺序存储数组的基本操作*/
Status InitArray(Array *A,int dim,...) /*构造数组A,...代表各维下标值,是不确定的*/
{
int elemtotal=1,i; /*elemtotal是元素个数的总值*/
va_list ap; /*ap是定义的宏类型的变量,它是一个指向第一个参数地址的指针*/
if(dim<1||dim>MAX_ARRAY_DIM) /*判断维界是否合法*/
return ERROR;
(*A).dim=dim;
(*A).bounds=(int *)malloc(dim*sizeof(int));
if(!(*A).bounds) /*分配存储失败*/
exit(OVERFLOW);
va_start(ap,dim); /*初始化宏*/
for(i=0;i<dim;i++)
{
(*A).bounds[i]=va_arg(ap,int); /*取出其值*/
if((*A).bounds[i]<0) /*如果维界不合法,则退出*/
return UNDERFLOW; /*在math.h中定义为4*/
elemtotal*=(*A).bounds[i]; /*元素总数等于各维界的乘积*/
}
va_end(ap);
(*A).base=(ElemType *)malloc(elemtotal*sizeof(ElemType));
if(!(*A).base) /*分配存储失败*/
exit(OVERFLOW);
(*A).constants=(int *)malloc(dim*sizeof(int));
if(!(*A).constants) /*分配存储失败*/
exit(OVERFLOW);
(*A).constants[dim-1]=1;
for(i=dim-2;i>=0;i--)
(*A).constants[i]=(*A).bounds[i+1]*(*A).constants[i+1];
return OK;
}
/*销毁数组*/
Status DestroyArray(Array *A)
{
if((*A).base)
{
free((*A).base);
(*A).base=NULL;
}
else
return ERROR;
if((*A).bounds)
{
free((*A).bounds);
(*A).bounds=NULL;
}
else
return ERROR;
if((*A).constants)
{
free((*A).constants);
(*A).constants=NULL;
}
else
return ERROR;
return OK;
}
/*若ap指示的各下标值合法,则求出该元素在A中的相对地址off*/
Status Locate(Array A,va_list ap,int *off)
{
int i,ind;
*off=0;
for(i=0;i<A.dim;i++)
{
ind=va_arg(ap,int);
if(ind<0||ind>=A.bounds[i])
return OVERFLOW;
*off+=A.constants[i]*ind; /*当你编译执行后看到结果就好理解了*/
}
return OK;
}
/*...表示数组各维的下标值,如果合法,则将每个值相应赋值给e*/
Status Value(ElemType *e,Array A,...)
{
va_list ap;
Status result;
int off;
va_start(ap,A);
if((result=Locate(A,ap,&off)==OVERFLOW))
return result;
*e=*(A.base+off);
return OK;
}
/*将e的值赋值给数组相应的元素*/
Status Assign(Array *A,ElemType e,...)
{
va_list ap;
Status result;
int off;
va_start(ap,e);
if((result=Locate(*A,ap,&off)==OVERFLOW))
return result;
*((*A).base+off)=e;
return OK;
}
int main()
{
Array A;
int i,j,k,*p,dim=3,bound1=3,bound2=4,bound3=2;
ElemType e,*p1;
InitArray(&A,dim,bound1,bound2,bound3);
p=A.bounds;
printf("A.bounds=");
for(i=0;i<dim;i++)
printf("%d",*(p+i));
p=A.constants;
printf("\nA.constants=");
for(i=0;i<dim;i++)
printf("%d ",*(p+i));
printf("\n%d页%d行%d列矩阵元素如下:\n",bound1,bound2,bound3);
for(i=0;i<bound1;i++)
{
for(j=0;j<bound2;j++)
{
for(k=0;k<bound3;k++)
{
Assign(&A,i*100+j*10+k,i,j,k);
Value(&e,A,i,j,k);
printf("A[%d][%d][%d]=%2d ",i,j,k,e);
}
printf("\n");
}
printf("\n");
}
p1=A.base;
printf("A.base=\n");
for(i=0;i<bound1*bound2*bound3;i++)
{
printf("%4d",*(p1+i));
if(i%(bound2*bound3)==bound2*bound3-1)
printf("\n");
}
DestroyArray(&A);
getchar();
}

算法的时间复杂度分析
InitArray函数的时间复杂度为O(n);
DestroyArray函数的时间复杂度为O(1);
LocateArray函数的时间复杂度为O(n);
SetArray函数的时间复杂度为O(n);
GetArray函数的时间复杂度为O(n);
SetArray函数和GetArray函数的时间复杂度主要受LocateArray函数影响。
4.4.2数组的顺序存储












4.4.3特殊矩阵的压缩存储


对称矩阵


三角矩阵

对角矩阵


稀疏矩阵






4.5 广义表



4.5.1性质


4.5.2与线性表的区别

4.5.3基本运算

4.6案例分析与实现
【案例4.1】: 病毒感染检测



void Virus detection ()
{//利用 BF 算法实现病毒检测
ifstream inFile("病毒感染检测输入数据. txt");
ofstream outFile("病毒感染检测输出结果. txt");
inFile>>num; //读取待检测的任务数
while(num--){ //依次检测每对病毒 DNA 和人的 DNA 是否匹配
inFile>>Virus.ch+1; //读取病毒 DNA 序列, 字符串从下标 1 开始存放
inFile>>Person.ch+1; //读取人的 DNA 序列
Vir=Virus.ch; //将病毒 DNA 临时暂存在 Vir 中 , 以备输出
flag=O; //用来标识是否匹配, 初始为0, 匹配后为非0
m=Virus.length; //病毒 DNA 序列的长度是 m
for (i=m+1, j=1; j<=m; j++) //将病毒字符串的长度扩大2倍
Virus.ch[i++]=Virus.ch[j]; //添加结束符号
Virus.ch[2*m+1]='\0';
for(i=O;i<m;i++){ //依次取得每个长度为m 的病毒 DNA 环状字符串 temp
for (j=1; j<=m; j++)
temp.ch[j] =Virus.ch[i+j];
temp.ch[m+1]='\0'; //添加结束符号
flag=Index_BF (Person, temp, 1); //模式匹配
if(flag) break; //匹配即可退出循环
}//for
if (flag)
outFile<<Vir+1<<" "<<Person. ch+1<<" "<<"YES"<<endl;
else
outFile<<Vir+1<<" "<<Person.ch+1<<" "<<"NO"<<endl;
}//while
}
算法设计题
( 1)写一个算法统计在输入字符串中各个不同字符出现的频度并将结果存入文件 (字符串中的合法字符为 A-Z 这 26 个字母和 0-9 这 10 个数字)。
[ 题目分析 ] 由于字母共 26 个,加上数字符号 10 个共 36 个,所以设一长 36 的整型数组,
前 10 个分量存放数字字符出现的次数, 余下存放字母出现的次数。 从字符串中读出数字字符
时,字符的 ASCII 代码值减去数字字符 ‘0’的 ASCII 代码值,得出其数值 (0…9) ,字母的
ASCII 代码值减去字符‘ A’的 ASCII 代码值加上 10 ,存入其数组的对应下标分量中。遇其它
符号不作处理,直至输入字符串结束。
[ 算法描述 ]
#include <stdio.h>
#include <iostream>
using namespace std;
void Count()
// 统计输入字符串中数字字符和字母字符的个数。
{
int i , num[36] ;
char ch ;
for ( i = 0; i<36 ; i++ )
num[i] = 0; // 初始化
while (( ch = getchar ()) != '#') // ‘ #’表示输入字符串结束。
if ('0' <=ch<= '9')
{i=ch - 48;num[i]++ ;} // 数字字符
else if ('A' <=ch<= 'Z')
{i=ch-65+10;num[i]++ ;} // 字母字符
for ( i=0 ; i<10 ; i++ ) // 输出数字字符的个数
cout<< "数字" <<i<< "的个数=" <<num[i]<<endl;
for ( i = 10 ; i<36 ; i++ ) // 求出字母字符的个数
cout<< "字母字符" <<i+55<< "的个数=" <<num[i]<<endl;
}
int main()
{
Count();
return 0;
}

浙公网安备 33010602011771号