CH4-串、数组和广义表


20220111141455

4.1 串的定义

20220111144240

20220111155240

20220111155349

20220111155628

4.2 案例引入

20220111155736

20220111155853

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

20220111160154

20220111160230

20220111160307

4.3.1 顺序串

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

4.3.2 链串

20220111160517

#define CHUNKSIZE 80	//块的大小可由用户定义
typedef struct Chunk{
    char ch[CHUNKSIZE];
    struct Chunk *next;
}Chunk;

typedef struct{
    Chunk *head,*tail;	//串的头指针和尾指针
    int curlen;			//串的当前长度
}LString;				//字符串的块链结构

4.3.3模式匹配算法

20220111161137

BF算法

20220111161245

20220111161431

20220111161513

20220111161613

20220111161836

#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;			//模式匹配不成功
}

20220121201154

20220111162349

KMP算法

20220111162528

20220111162929

20220111163033

20220111163143

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; 				/*返回不匹配标志*/
}

20220111163716

20220111164423

20220111164147

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 数组

20220111175128

20220111175215

20220111182445

20220111182613

4.4.1抽象数据类型定义

20220111182833

20220111183040

20220111183213

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();
}

20220122183810

算法的时间复杂度分析

InitArray函数的时间复杂度为O(n);

DestroyArray函数的时间复杂度为O(1);

LocateArray函数的时间复杂度为O(n);

SetArray函数的时间复杂度为O(n);

GetArray函数的时间复杂度为O(n);

SetArray函数和GetArray函数的时间复杂度主要受LocateArray函数影响。

4.4.2数组的顺序存储

20220111183520

20220111183703

20220111184012

20220111184249

20220111184331

20220111184438

20220111184542

20220111184712

20220111184808

20220111184837

20220111184909

20220111184934

4.4.3特殊矩阵的压缩存储

20220111185113

20220111185355

对称矩阵

20220111185502

20220111185553

三角矩阵

20220111185813

对角矩阵

20220111190029

20220111190257

稀疏矩阵

20220112163730

20220112163949

20220112164122

20220112164333

20220112164452

20220112164503

4.5 广义表

20220112164750

20220112165121

20220112165241

4.5.1性质

20220112165448

20220112165705

4.5.2与线性表的区别

20220112165818

4.5.3基本运算

20220112170057

4.6案例分析与实现

【案例4.1】: 病毒感染检测

20220112170431

20220112170513

20220112170536

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;
}

20220123093417

posted @ 2022-01-28 14:08  肖雄_greek  阅读(104)  评论(0)    收藏  举报