#2线性关系

发布于 2024-11-03  711 次阅读



一、定义
线性表:线性表是具有相同的数据类型的n(n>=0)个数据元素的有限序列。
表长:线性表中元素的个数n称为表长。当n=0时,线性表为空表。
二、基本操作
初始化:InitList(&L)
插入:ListInsert(&L,i,e)
删除:ListDelete(&L,i,&e)
查找:GetElem(L,i)/LocateElem(L,e)
求表长:Length(L)
判空:Empty(L)
三、存储结构
(一)顺序表
1、顺序表的定义
顺序表是使用顺序存储方式实现的线性表。

//静态分配实现顺序表
typedef struct{
    ElemType data[MaxSize];
    int Length;
}SqList;
//动态分配实现顺序表
typedef struct{
    ElemType *data;
    int Length,MaxSize;
}SeqList;

2、顺序表的基本操作
初始化

//静态分配的初始化
bool InitList(SqList &L){
    L.Length=0;
    return true;
}
//动态分配的初始化
bool InitList(SeqList &L){
    L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);
    L.Length=0;
    L.MaxSize=InitSize;
    return true;
}
//动态分配下的扩容函数
bool IncreaseSize(SeqList &L,int Len){
    ElemType *p=L.data;
    L.data=(ElemType*)malloc(sizeof(ElemType)*(L.MaxSize+Len));
    for(int i=0;i<L.Length;i++)
    {
        L.data[i]=p[i];
    }
    L.MaxSize+=Len;
    free(p);
    return true;
}

插入

//按位序插入
bool ListInsert(SqList &L,int i,ElemType e){
    if(i<1||i>L.Length+1)
    {
        return false;
    }
    if(L.Length==L.MaxSize)
    {
        return false;
    }
    for(int j=L.Length;j>=i;j--)
    {
        L.data[j]=L.data[j-1];
    }
    L.[i-1]=e;
    L.Length++;
    return true;
}

删除

//按位序删除
bool ListDelete(SqList &L,int i,ElemType &e){
    if(i<1||i>L.Length)
    {
        return false;
    }
    e=L.data[i-1];
    for(int j=i;j<L.Length;j++)
    {
        L.data[j-1]=L.data[j];
    }
    L.length--;
    return true;
}

查找

//按位查找
ElemType GetElem(SqList L,int i){
    return L.data[i-1];
}
//按值查找
int LocateElem(SqList L,ElemType e){
    for(int i=0;i<L.Length;i++)
    {
        if(e==L.data[i])
        {
            return i+1;
        }
    }
    return 0;
}

求表长

int Length(SqList L){
    return L.Length;
}

判空

bool Empty(SqList L){
    if(L.Length==0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

(二)链表
1、单链表
(1)单链表的定义
单链表是使用链式存储方式实现的线性表。每个结点之间通过一个单向的指针连接。

//单链表结点定义
typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;

(2)单链表的基本操作
初始化

//携带头结点
bool InitList(LinkList &L){
    L=(LNode*)malloc(sizeof(LNode));
    L->next=NULL;
    return true;
}
//不带头结点
bool InitList(LinkList &L){
    L=NULL;
    return true;
}

插入

//按位序插入
bool ListInsert(LinkList &L,int i,ElemType e){
    if(i<1)
    {
        return false;
    }
    LNode *p=L,*s;
    if(i=1)
    {
        s=(LNode*)malloc(sizeof(LNode));
        s->data=e;
        s->next=L;
        L=s;
        return true;
    }
    //若不带头结点,插入第一个结点特殊处理
    int j=0;
    while(p!=NULL&&j<i-1)
    {
        p=p->next;
        j++;
    }
    if(p==NULL)
    {
        return false;
    }
    s=(LNode*)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
}
//指定结点后插
bool InsertNextNode(LNode *p,ElemType e){
    if(p==NULL)
    {
        return false;
    }
    LNode *s=(LNode*)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
}
//指定结点前插
bool InsertPriorNode(LNode *p,ElemType e){
    if(p==NULL)
    {
        return false;
    }
    LNode *s=(LNode*)malloc(sizeof(LNode));
    s->data=p->data;
    p->data=e;
    s->next=p->next;
    p->next=s;
    return true;
}

删除

//按位序删除
bool ListDelete(LinkList &L,int i,ElemType &e){
    if(i<1)
    {
        return false;
    }
    LNode *p=L,*s;
    int j=0;
    while(p!=NULL&&j<i-1)
    {
        p=p->next;
        j++;
    }
    if(p==NULL)
    {
        return false;
    }
    s=p->next;
    if(s==NULL)
    {
        return false;
    }
    e=s->data;
    p->next=s->next;
    free(s);
    return true;
}
//指定结点删除
bool DeleteNode(LNode *p,ElemType &e){
    if(p==NULL)
    {
        return false;
    }
    e=p->data;
    LNode *s=p->next;
    p->data=s->data;
    p->next=s->next;
    free(s);
    return true;
}

查找

//按位查找
LNode* GetElem(LinkList L,int i){
    if(i<0)
    {
        return NULL;
    }
    LNode *p=L;
    int j=0
    while(p!=NULL&&j<i)
    {
        p=p->next;
        j++;
    }
    return p;
}
//按值查找
LNode* LocateElem(LinkList L,ElemType e){
    LNode *p=L;
    while(p!=NULL&&p->data!=e)
    {
        p=p->next;
    }
    return p;
}

求表长

int Length(LinkList L){
    int j=0;
    LNode *p=L;
    while(p->next!=NULL)
    {
        p=p->next;
        j++;
    }
    return j;
    //若不带头结点,返回j-1
}

判空

bool Empty(LinkList L){
    if(L->next==NULL)
    //若不带头结点,判断条件为L==NULL
    {
        return true;
    }
    else
    {
        return false;
    }
}

2、双链表
(1)双链表的定义
双链表是使用链式存储实现的线性表。在单链表的基础上,添加了向前的指针。

typedef struct DNode{
    ElemType data;
    struct DNode *prior,*next;
}DLNode,*DLinkList;

(2)双链表的基本操作
初始化

//带头结点
bool InitList(DLinkList &L){
    L=(DNode*)malloc(sizeof(DNode));
    L->next=NULL;
    L->prior=NULL;
}

插入

//按位序插入
bool ListInsert(DLinkList &L,int i,ElemType e){
    if(i<1)
    {
        return false;
    }
    DNode *p=L,*s;
    int j=0;
    while(p!=NULL&&j<i-1)
    {
        p=p->next;
        i++;
    }
    if(p==NULL)
    {
        return false;
    }
    s=(DNode*)malloc(sizeof(DNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    s->prior=p;
    if(s->next!=NULL)
    {
        s->next->prior=s;
    }
    return true;
}
//指定结点后插
bool InsertNextNode(DLNode *p,ElemType e){
    if(p==NULL)
    {
        return false;
    }
    DNode *s=(DNode*)malloc(sizeof(DNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    s->prior=p;
    if(s->next!=NULL)
    {
        s->next->prior=s;
    }
    return true;
}
//指定结点前插
bool InsertPriorNode(DLnode *p,ElemType e){
    if(p==NULL)
    {
        return false;
    }
    p=p->prior;
    DNode *s=(DNode*)malloc(sizeof(DNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    s->prior=p;
    s->next->prior=s;
    return true;
}

删除

//按位序删除
bool ListDelete(DLinkList &L,int i,ElemType &e){
    if(i<1)
    {
        return false;
    }
    DNode *p=L,*s;
    int j=0;
    while(p!=NULL&&j<i-1)
    {
        p=p->next;
        j++;
    }
    if(p==NULL)
    {
        return false;
    }
    s=p->next;
    if(s==NULL)
    {
        return false;
    }
    e=s->data;
    s->next=p->next;
    if(s->next!=NULL)
    {
        s->next->prior=p;
    }
    free(s);
    return true;
}
//指定结点删除
bool DeleteNode(DNode *p,ElemType &e){
    if(p==NULL)
    {
        return false;
    }
    e=p->data;
    DNode *s=p->prior;
    s->next=p->next;
    if(p->next!=NULL)
    {
        p->next->prior=s;
    }
    free(p);
    return true;
}

//查找

//按位查找
DNode* GetElem(DLinkList L,int i){
    if(i<1)
    {
        return NULL;
    }
    DNode *p=L;
    int j=0;
    while(p!=NULL&&j<i)
    {
        p=p->next;
        j++;
    }
    return p;
}
//按值查找
DNode* LocateElem(DLinkList L,ElemType e){
    DNode *p=L;
    while(p!=NULL&&e!=p->data)
    {
        p=p->next;
    }
    return p;
}

求表长

int Length(DLinkList L){
    DNode *p=L;
    int j=0;
    while(p->next!=NULL)
    {
        p=p->next;
        j++;
    }
    return j;
}

判空

bool Empty(DLinkList L){
    if(L->next==NULL&&L->prior==NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}

3、循环链表
(1)循环单链表
A、循环单链表的定义
循环单链表是使用链式存储实现的线性表,在单链表的基础上,使得最后一个结点的指针指向头结点。
B、循环单链表的基本操作
初始化

bool InitList(LinkList &L){
    L=(LNode*)malloc(sizeof(LNode));
    L->next=L;
    return true;
}

(2)循环双链表
A、循环双链表的定义
循环双链表是使用链式存储实现的线性表,在双链表的基础上,使得最后一个结点的向后指针指向头结点,头结点的向前指针指向最后一个结点。
B、循环双链表的基本操作
初始化

bool InitList(DLinkList &L){
    L=(DNode*)malloc(sizeof(DNode));
    L->next=L;
    L->prior=L;
    return true;
}

4、静态链表
静态链表的定义
静态链表是使用顺序存储的方式实现的逻辑上的链表。

typedef struct{
    ElemType data;
    int next;
}SLinkList[MaxSize];

四、应用线性表
(一)栈
1、栈的定义
栈是一种只允许在一端进行插入删除操作的线性表。
2、栈的基本操作
初始化:InitStack(&S)
入栈:Push(&S,e)
出栈:Pop(&S,&e)
读栈顶元素:GetTop(S,&e)
判空:Empty(S)
3、栈的存储结构
(1)顺序栈
A、顺序栈的定义
顺序栈是用顺序存储方式实现的栈。

typedef struct{
    ElemType data[MaxSize];
    int Top;
}SqStack;

B、顺序栈的基本操作
初始化

bool InitStack(SqStack &S){
    S.Top=-1;
    return true;
}

入栈

bool Posh(SqStack &S,ElemType e){
    if(S.Top==MaxSize-1)
    {
        return false;
    }
    S.data[++S.Top]=e;
    return true;
}

出栈

bool Pop(SqStack &S,ElemType &e){
    if(S.Top==-1)
    {
        return false;
    }
    e=S.data[S.Top--];
    return true;
}

读栈顶元素

bool GetTop(SqStack S,ElemType &e){
    if(S.Top==-1)
    {
        return false;
    }
    e=S.data[S.Top];
    return true;
}

判空

bool Empty(SqStack S){
    if(S.Top==-1)
    {
        return true;
    }
    else
    {
        return false;
    }
}

C、共享栈
共享栈使用一片空间存储两个顺序栈。

//定义
typedef struct{
    ElemType data[MaxSize];
    int Top1,Top2;
}ShStack;
//初始化
bool InitStack(ShStack &S){
    S.Top1=-1;
    S.Top2=MaxSize;
    return true;
}

(2)链栈
A、链栈
链栈是使用链式存储实现的栈。

typedef struct LinkNode{
    ElemType data;
    struct LinkNode *next;
}LinkNode,*LStack;

B、链栈的基本操作
初始化

bool InitStack(LStack &S){
    S=(LinkNode*)malloc(sizeof(LinkNode));
    S->next=NULL;
    return true;
}

入栈

bool Push(LStack &S,ElemType e){
    LinkNode *p=(LinkNode*)malloc(sizeof(LinkNode));
    p->data=e;
    p->next=s->next;
    s->next=p;
    return true;
}

出栈

bool Pop(LStack &S,ElemType &e){
    if(s->next==NULL)
    {
        return false;
    }
    LinkNode *p=s->next;
    e=p->data;
    s->next=p->next;
    free(p);
    return true;
}

读栈顶元素

LinkNode* GetTop(LStack S){
    return S->next;
}

判空

bool Empty(LStack S){
    if(S->next==NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}

4、栈的应用
(1)括号匹配

bool BracketCheck(char str[],int length){
    SqStack S;
    InitStack S;
    for(int i=0,i<length;i++)
    {
        if(str[i]=='('||str[i]=='['||str[i]='{')
        {
            Push(S,str[i]);
        }
        else
        {
            if(Empty(S))
            {
                return false;
            }
            char Top;
            Pop(S,Top);
            if(str[i]==')'&&Top!='(')
            {
                return false;
            }
            if(str[i]==']'&&Top!='[')
            {
                return false;
            }
            if(str[i]=='}'&&Top!='{')
            {
                return false;
            }
        }
    }
    return Empty(S);
}

(2)表达式求值
A、后缀表达式
(A-1)中缀转后缀
自左向右扫描,直至末尾:
①若扫描到操作数,直接加入后缀表达式。
②若扫描到界限符,
a.“(”直接入栈。
b.“)”依次弹出栈顶元素,直至弹出“(”。
③若扫描到运算符,依次弹出栈中优先级不低于当前运算符的所有运算符,直到碰到“(”或栈空,最后将当前运算符加入表达式。
(A-2)后缀计算
自左向右扫描,直至末尾:
①若扫描到操作数,入栈。
②若扫描到运算符,弹出两个栈顶元素,计算并重新入栈。
B、前缀表达式
(B-1)中缀转前缀
自右向左扫描,规则一致。
(B-2)前缀计算
自右向左扫描,规则一致。
C、中缀表达式
中缀计算
自左向右扫描,直至末尾:
①若扫描到操作数,压入操作数栈。
②若扫描到运算符或界限符,依次弹出运算符栈中优先级不低于当前运算符的所有运算符,直到碰到“(”或栈空,每弹出一个运算符,弹出两个操作数进行运算并压入操作数栈。
最后将当前运算符加入运算符栈。
(3)递归
(二)队列
1、队列的定义
队列是一种只允许在一端输入,在另一端删除的线性表。
2、队列的基本操作
初始化:InitQueue(&Q)
入队:EnQueue(&Q,e)
出队:DeQueue(&Q,&e)
读队头元素:GetHead(Q,&e)
判空:Empty(Q)
3、队列的存储结构
(1)顺序队列
A、顺序队列的定义
顺序队列是使用顺序存储方式实现的队列。

typedef struct{
    ElemType data[MaxSize];
    int front,rear;
}SqQueue;

B、顺序队列的基本操作
初始化

bool InitQueue(SqQueue &Q){
    Q.front=Q.rear=0;
    return true;
}

入队

bool EnQueue(SqQueue &Q,ElemType e){
    if((Q.rear+1)%MaxSize==Q.front)
    {
        return false;
    }
    Q.data[Q.rear]=e;
    Q.rear=(Q.rear+1)%MaxSize;
    return true;
}

出队

bool DeQueue(SqQueue &Q,ElemType &e){
    if(Q.front==Q.rear)
    {
        return false;
    }
    e=Q.data[Q.front];
    Q.front=(Q.front+1)%MaxSize;
    return true;
}

读队头元素

bool GetHead(SqQueue Q,ElemType &e){
    if(Q.front==Q.rear)
    {
        return false;
    }
    e=Q.data[Q.front];
    return true;
}

判空

bool Empty(SqQueue Q){
    if(Q.front==Q.rear)
    {
        return true;
    }
    else
    {
        return false;
    }
}

(2)链式队列
A、链式队列的定义
链式队列是使用链式存储方式实现的队列。

//结点定义
typedef struct LinkNode{
    ElemType data;
    struct LinkNode *next;
}LinkNode;
//队头队尾指针定义
typedef struct{
    LinkNode *front,*rear;
}LinkQueue;

B、链式队列的基本操作
初始化

bool InitQueue(LinkQueue &Q){
    Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));
    Q.rear->next=NULL;
    return true;
}

入队

bool EnQueue(LinkQueue &Q,ElemType e){
    LinkNode *p=(LinkNode*)malloc(sizeof(LinkNode));
    p->data=e;
    p->next=NULL;
    Q.rear->next=p;
    Q.rear=p;
    return true;
}

出队

bool DeQueue(LinkQueue &Q,ElemType &e){
    if(Q.front==Q.rear)
    {
        return false;
    }
    LinkNode *p=Q.front->next;
    e=p->data;
    Q.front->next=p->next;
    if(p->next==NULL)
    {
        Q.rear==Q.front;
    }
    free(p);
    return true;
}

读队头元素

LinkNode* GetHead(LinkQueue Q){
    return Q.front->next;
}

判空

bool Empty(LinkQueue Q){
    if(Q.front==Q.rear)
    {
        return true;
    }
    else
    {
        return false;
    }
}

4、双端队列
允许或部分允许从两端进行插入和删除操作的队列。具体有:
双端队列:允许从两端进行插入和删除
输入受限的双端队列:允许一端插入,两端删除
输出受限的双端队列:允许两端插入,一端删除
(三)串
1、串的定义
串:即字符串,是由0个或多个字符组成的有限序列。
串长:串中字符的个数n称为串的长度,n=0时为空串。
子串:串中任意个连续字符组成的子序列。
2、串的基本操作
求子串:SubString(&Sub,S,pos,len)
比较:StrCompare(S,T)
定位:Index(S,T)
3、串的存储结构
(1)顺序串
顺序串的定义
顺序串是使用顺序存储实现的串。

typedef struct{
    char ch[MaxLen];
    int length;
}SString;

(2)链串
链串的定义
链串是使用链式存储实现的串。

typedef struct StringNode{
    char ch;
    struct StringNode *next;
}StringNode,*String;

(3)基本操作
求子串

bool SubString(SString &Sub,SString S,int pos,int len){
    if(pos+len-1>S.length)
    {
        return false;
    }
    for(int i=pos;i<pos+len;i++)
    {
        Sub.ch[i]=S.ch[i];
    }
    Sub.length=len;
    return true;
}

比较

int StrCompare(SString S,SString T){
    for(int i=0;i<=S.length&&i<=T.length;i++)
    {
        if(S.ch[i]!=T.ch[i])
        {
            return S.ch[i]-T.ch[i];
        }
    }
    return S.length-T.length;
}

定位

int Index(SString S,SString T){
    int i=1,n=S.length,m=T.length;
    SString sub;
    while(i<=n-m+1)
    {
        SubString(sub,S,i,m);
        if(StrCompare(sub,T)!=0)
        {
            i++;
        }
        else
        {
            return i;
        }
    }
    return 0;
}

4、字符串的模式匹配
(1)朴素算法模式匹配
朴素算法模式匹配是从主串S的第i位开始,依次与模式串T进行逐位对比,一般来说i的初始值为1.
若对比失败,则回退i的值,并使得i=i+1,再次开始对比,直到对比成功或全部对比失败。
(2)KMP算法
KMP算法是预先计算出模式串对应的next数组,通过next数组调整模式串对比指针j的位置,而主串指针i不回退。


学习是一段漫长的旅途