线性表主要由顺序表示或链式表示。在实际应用中,常以栈、队列、字符串等特殊形式使用
定义
线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
存储结构
顺序表(顺序表示)
1.定义顺序表
typedef struct Sqlist{
Elemtype *elem;
int length;
int listsize;
}Sqlist; //定义顺序表
2.初始化顺序表
Status InitSqlist(Sqlist &L){
//初始化顺序表
L.elem=(Elemtype *)malloc(List_init_size*sizeof(Elemtype));
if(!L.elem)exit(OVERFLOW);//exit 退出系统
L.length=0;//清空顺序表长度
L.listsize=List_init_size;//初始存储容量
return OK;
}
3.插入操作
Status SqlistInsert(Sqlist &L){
//插入运算
printf("请输入插入数据的位置\n");
int i;
scanf("%d",&i);
while(i<1||i>L.length+1){
if(i<1||i>L.length+1==0)break;
int i2;
printf("error:插入位置错误\n请重新输入插入的位置:\n");
scanf("%d",&i2);
i=i2;
}
if(L.length>=L.listsize)
{
Elemtype *newbase;
newbase=(Elemtype *)realloc(L.elem,LISTNCREMENT*sizeof(Elemtype));
if(!newbase)return ERROR;
L.elem=newbase;
L.listsize+=LISTNCREMENT;
}
printf("请输入该学生数据\n");
Elemtype e;
scanf("%s%s%d",e.no,e.name,&e.score);
Elemtype *p,*q;
q=&(L.elem[i-1]);//指向插入位置i
for(p=&(L.elem[L.length-1]);p>=q;--p)
*(p+1)=*p;//从最后一个元素开始往后移,移至第i个位置
*q=e;
++L.length;
return OK;
}
4.删除操作
Status DeleteSqlist(Sqlist &L){
//删除运算
printf("请输入要删除数据的位置\n");
int i;
scanf("%d",&i);
Elemtype e;
while(i<1||i>L.length){
if(i<1||i>L.length==0)break;
int i2;
printf("error:删除位置错误\n请重新输入删除的位置:\n");
scanf("%d",&i2);
i=i2;
}
e=L.elem[i-1];
Elemtype *p,*q;
q=&L.elem[i];
for(p=q;p<=&L.elem[L.length-1];p++){*(p-1)=*p;}
L.length--;
return OK;
}
5.查找操作
Status SearchSqlist(Sqlist &L){
//查找运算
char g[12];
printf("请输入要查询的学生的学号\n");
scanf("%s",g);
int i=0,j;
for(j=0;j<=L.length-1;j++){
if(strcmp(g,L.elem[j].no)==0)printf("该学生信息为:\n%s\t%s\t%d\n",L.elem[j].no,L.elem[j].name,L.elem[j].score);
else i++;
}
if(i==L.length){
printf("error:该学生不存在\n请重新输入要查询的学生:\n");
SearchSqlist(L);
}
return OK;
}
链表(链式表示)
1.定义结点类型
typedef struct LNode{
//定义结点类型
ElemType data;//数据域
struct LNode* next;//指针域 (递归定义数据类型)
}LNode;
2.定义链表
typedef LNode* LinkList; //定义链表类型,节点类型的指针类型就是链表
3.初始化链表
Status InitLNode(LinkList &L){
//初始化空链表
L=new LNode;//相等于L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
if(!L)return 0;
return OK;
}
4.插入操作
Status InsertLinkList(LinkList &L,int i,ElemType e){
//向第i个位置之前插入一个结点
int length=GetLength(L);
if(i<1||i>length+1)exit(ERROR);
LinkList p,q;
p=L;//p指向头节点
int j=1;
while(p && j<i){//p指向第i个元素前驱的时候停止
p=p->next;
++j;
}
//InitLNode(q);
q=new LNode;
q->data=e;
q->next=p->next;//新插入的元素的指针指向原来第i个元素
p->next=q;//第i-1个元素的指针指向新插入的元素
printf("插入成功!\n");
return OK;
5.删除操作
Status Delete(LinkList &L,int i,ElemType &e){
//删除第i个元素
int length=GetLength(L);
if(i<1||i>length)exit(ERROR);
LinkList p,q;
p=L;
int j=1;
while(p && j<i){//p指向第i个元素前驱的时候停止
p=p->next;
++j;
}
q=p->next;
e=q->data;//保存要删除的元素
p->next=q->next;//第i-1个元素指向第i+1个元素
printf("删除成功!\n");
return OK;
}
6.查找操作
Status GetElem(LinkList L,int i,ElemType &e){
//读取第i个元素的值
int length=GetLength(L);
if(i<1||i>length)exit(ERROR);
LinkList p;
p=L->next;
int j=1;
while(p && j<i){//p指向第i个元素前驱的时候停止
p=p->next;
++j;
}
e=p->data;
return OK;
}
7.创建含有n个结点的链表 (头插法)
Status CreatList_T(LinkList &L,int n){//创建含有n个结点的单链表 (头插法)
for(int i=0;i<n;i++){
LinkList p;
p=new LNode;//创建一个新的结点类型,p指向该空间,p就是该结点
printf("请输入数据\n");
scanf("%d",&p->data);
p->next=L->next;//新节点的后驱为上一个节点
L->next=p;//记录新结点的位置
}
}
8.创建含有n个结点的单链表 (尾插法)
Status CreatList_W(LinkList &L,int n){//创建含有n个结点的单链表 (尾插法)
LinkList r;
r=L;//尾指针指向头结点
for(int i=0;i<n;i++){
LinkList p;
p=new LNode;//创建一个新的结点类型,p指向该空间,p就是该结点
printf("请输入数据\n");
scanf("%d",&p->data);
p->next=NULL;//新结点的指针指向为空
r->next=p; //尾结点指向新的结点
r=p;//记录新结点的位置,新节点就成为尾结点
}
}
实际应用
栈、
顺序栈
1.定义顺序栈
typedef struct SqStack{
ElemType *base; //栈底指针
ElemType *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
- 初始化顺序栈
Status InitStack(SqStack &S)
{
S.base=new ElemType[NUM]//为顺序栈分配一个最大容量为NUM的数组空间
if(!S.base)return 0; //存储分配失败
S.top=S.base; //top初始为base ,空栈
S.stacksize=NUM; //stacksize设置为栈的最大容量NUM
return 1;
}
- 顺序栈的入栈
Status Push(SqStack &S,ElemType e){
if(S.top-S.size==S.stacksize){//栈满
S.base=(ElemType*)realloc(S.base,sizeof(ElemType)*S.stackszie*2)
if(!S.base)return 0;
S.top=S.base;
S.stacksize*=2;
}
*S.top=e;
S.top++;
return 1;
}
- 顺序栈的出栈
Status Pop(Sqstack &S,ElemType &e){
if(S.top==S.base)return 0;//栈空
S.top--; //因为top指针一般指向下一个空间
e=*S.top;
return 1;
}
5 取顺序栈的栈顶元素
Staus GetTop(SqStack &S){
//返回S的栈顶元素,不修改栈顶指针
if(S.top!=S.base)return *(S.top-1);//栈非空时执行
}
- 求顺序栈的长度 S.top-S.base;
- 清空顺序栈 S.top=S.base;
- 销毁顺序栈
Status DestroyStack(SqStack &S){
if(S.base){
free(S.base);
S.stacksize=0;
S.base=S.top=NULL;
}
return 1;
}
链栈
1.定义链栈的结点和链表
typedef struct StackNode{
ElemType data;
struct StackNode *next;
}StackNode;
typedef StackNode* LinkStack;//定义链栈链表
- 链栈的初始化
void InitStack(LinkStack &S)
{
S=NULL;
}
3.判断链栈是否为空
Status StackEmpty(LinkStack &S)
{
if(!S)return 0;
return 1;
}
- 链栈进栈
Status Push(LinkStack &S,ElemType e)
{
p=(LinkStack)malloc(sizeof(StackNode))
if(!p)return 0;
p->data=e;
p->next=S;
S=p;
return 1;
}
- 链栈出栈
Status Pop(LinkStack &S,ElemType e)
{
if(!S)return 0;//栈空
e=S->data;
LinkStack p;
p=S;
S=S->next;
delete p;//p=S指向栈顶,delete p,删除该栈顶空间
return 1;
}
- 取栈顶元素
Status GetTop(StackList &S){
if(!S)return 0;//栈空
return S->data;
}
队列、
队列是一种先进先出的线性表,它只允许在表的一端进行插入,而在另一端删除元素。
循环队列-------队列的顺序表示
1.定义顺序队列
typedef struct
{
QElemType *base;//存储空间的首地址
int front;//头指针
int rear;//尾指针
}SqQueue;
- 初始化顺序队列
Status InitQueue(SqQueue &Q)
{
Q.base=new QElemType[MAXSIZE];//为队列分配一个最大容量为MAXSIZE的数组空间
if(!Q.base)exit(OVERFLOW);//分配空间失败
Q.front=Q.rear=0;//头指针和尾指针置为零,队列为空
return OK;
}
3.求队列长度
int QueueLength(SqQueue Q)
{
return(Q.rear-Q,front+MAXQSIZE)%MAXQSIZE; //少用一个存储空间
}
- 入队
Status EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear+1)%MAXQSIZE==Q.front)//少用一个存储空间,表明队满
return ERROR;
Q.base[Q.rear]=e; //新元素插入队尾
Q,rear=(Q.rear+1)%MAXSIZE;//队尾指针加1
return OK;
}
- 出队
Status DeQueue(SqQueue &Q,QElemType &e)
{
if(Q.front==Q.rear)return ERROR;//队空
e=Q.base[Q.front];//保存队头元素
Q.front=(Q.front+1)%MAXSIZE//队头指针加1
return OK;
}
6.取循环队列的队头元素
SElemType GetHead(SqQueue Q)
{//返回Q的队头元素,不修改队头指针
if(Q.front!=Q.rear)//队列非空
return Q.base[Q.front];//返回队头元素的值,队头指针不变
}
链队–队列的链式表现
1. 定义结点类型,结点指针类型
typedef struct QNode{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
2.定义链队
typedef struct{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
3.初始化链队
Status InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=new QNode;//生成新结点作为头结点,队头和队尾指针都指向此结点
Q.front->next=NULL;//头指针的指针域置空
return OK;
}
4.入队
Status EnQueue(LinkQueue &Q,QElemType e)
{
p=new QNode;//为入队元素分配结点空间
if(!p)exit(OVERFLOW);
p->data=e;
p->next=NULL;
Q.rear->next=p;//将新结点插入到队尾
Q.rear=p;//修改队尾指针
return OK;
}
5.出队
Status DeQueue(LinkQueue &Q,QELemType &e)
{
if(Q.front==Q.rear)reurn ERROR;//队列为空
p=Q.front->next;//p指向队头元素
e=p->data;//保存队头元素的值
Q.front->next=p->next;//修改头指针
if(Q.rear==p)Q.rear=Q.front;//最后一个元素被删,队尾指针指向头结点
delete p;//释放空间
return OK;
}
6.取队头元素
与循环队列一样,当队列非空时,此操作返回当前队头元素的值,队头指针保持不变
SElemType GetHead(LinkQueue Q)
{
if(Q.front!=Q.rear)//队列非空
return Q.front->next->data;//返回队头元素的值
}
7.销毁链队列
Status DestroyQueue(LinkQueue &Q)
{
while(Q.front){
Q.rear=Q.front->next;
free(Q.front);
Q.front=Q.rear;
}
return OK;
}
- 判断链队是否为空
Status QueueEmpty(LinkQueue Q)
{
return(Q.front==Q.rear);
}
字符串、
一、存储结构
1.串的顺序存储:用一组地址连续的存储单元存储串值得序列。
typedef unsigned char SString[Maxsize];
SString S;
2.串的堆顺序存储结构:
typedef struct{
char *ch;//若是非空串,按串长分配空间;否则ch=NULL
int length;//串长度
}HString;
3.串的链式存储结构
#define CHUNSIZE 80//自定义块的大小
typedef struct Chunk{//定义块类型
char ch[CHUNSIZE];
struct Chunk *next;
}Chunk;
typedef struct{//定义串类型
Chunk *head,*tail;//串的头指针和尾指针
int length; //串的当前长度
}LString
二、串的模式匹配算法
BF算法
Status BF(Sstring S,SsTring T,int pos){
int i,j=1;
i=pos;
while(i<S[0] && j<=T[0]){
if(i<=S[0] && j<=T[0]){++i;++j;}
else{i=i-j+2;j=1;}//回溯操作
}
if(j>T[0])return i-T[0];
else return 0;
}
KMP算法
Status Index_KMP(SString S,SString T,int pos){
i=pos;j=1;
while(i<=s[0] && j<=T[0]){
if(j==0 || s[i]==s[j]){++i;++j;}//不失配则继续比较后续字
else{j=next[j];}//S的i指针不回溯,从T的k位置开始匹配
}
if(j>T[0])return i-T[0];//子串结束,说明匹配成功
else return 0;
}
void GetNext(String T,int next[]){
int j,k;
j=1;k=0;
next[j]=k;
while(j<T[0]){//T[0]表示字符串长度
//当k=0时,j+1的next是k+1,即1;
//当T[k]=T[j] j+1的next是k+1
if(k==0 || T[k]==T[j]){
++j;
++k;
next[j]=k;
}
else
k=next[k];
}
}
void GetNextVal(Sstring T,int nextval[]){
int j=1,k=0;
nextval[j]=k;
while(j<T[0]){
if(k==0 || T[j]==T[k]){
j++;k++;
if(T[j]!=T[k])
nextval[j]=k;
else
nextval[j]=nextval[k];
}
else k=nextval[k];
}
}
nextval[j]计算步骤 (1)计算出next[j] = k值,
(1.1)如果Tj = Tk ,nextval[j] = nextval[k]
(1.2) 如果Tj != Tk,nextval[j] = next[j] = k.