数据结构-线性表(7.12)


写在开头

用于自己考研复习巩固

一、线性表基本操作

  • InitList(&L)-初始化表
  • Length(L)-求表长
  • LocateElem(L,e)-按值查找
  • GetElem(L,i)-按位查找
  • ListInsert(&L,i,e)-插入
  • ListDelete(&L,i,&e)-删除
  • printfList(L)-输出
  • Empty(L)-判空
  • DestroyList(&L)-销毁

&表C/C++中的引用调用,即对参数的修改结果要带回来

二、顺序表

2.1顺序表的实现

2.1.1静态数组

#define Maxsize 50           //定义最大长度
typedef struct
{
    ElemType data[Maxsize];  //静态数组存放数据元素
    int length;              //顺序表当前长度
} SqList;

//初始化顺序表
void InitList(SqList &L)
{
    for(int i=0; i<Maxsize; i++)
        L.data[i]=0;         //设置默认元素初始值,不然内存会有脏数据
    L.length=0;          //设置初始长度为0
}

缺点:数组的大小和空间事先固定。一旦空间满,加入新的数据就会产生溢出,导致程序崩溃。

2.1.2动态分配

//动态分配
#define InitSize 50     //长度的初始定义
typedef struct
{
    ElemType *data;     //动态分配数值的指针
    int Maxsize;        //顺序表最大容量
    int length;         //顺序表当前长度
} SqList;

//初始化顺序表
void InitList(SqList &L)
{
    //用malloc函数申请一片连续的储存空间
    L.data=(ElemType *)malloc(InitSize*sizeof(ElemType ));
    L.length=0;
    L.MaxSize=InitSize;

//空间不够,动态增加数组长度
void Increase(SqList &L,int len)
{
    int *p=L.data;
    L.data=(ElemType *)malloc((L.MaxSize+len)*sizeof(ElemType ));
    for(int i=0; i<L.length; i++)
        L.data[i]=p[i];             //将数据复制到新区域
    L.MaxSize+=len;                 //顺序表最大长度增加len
    free(p);                        //释放原空间
}

2.1.3小结

_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpYW5nc2VuYQ==,size_16,color_FFFFFF,t_70)

2.2顺序表的插入与删除

2.2.1顺序表的插入

//顺序表的插入(以静态数组为例)(1<=i<=length+1)
    bool LinkList(SqList &L,int i,ElemType e)
    {
        if(i<1||i>L.length+1)
            return false;
        if(i>=Maxsize)
            return false;
        for(int j=L.length; j>=i; j--)
            L.data[j]=L.data[j-1];
        L.data[i-1]=e;
        L.length++;
        return true;
    }

注意数组下标和位序

2.2.2顺序表的删除

//顺序表的删除
    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;
    }

注意&e,把删除的值e带回来

2.2.3小结

在这里插入图片描述

2.3顺序表的查找

2.3.1按位查找

//按位查找
    ElemType GetElem(SqList L,int i)
    {
        return L.data[i-1];
    }

2.3.2按值查找

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

1.在C语言中结构的比较不可以直接用==
2.但在《数据结构》考研初试中,手写代码可以用==,无论是基本数据类型还是结构类型

2.3.3小结

在这里插入图片描述

2.4易错试题

1.线性表的顺序存储结构是一种()
A.随机存取的顺序结构
B.顺序存取的顺序结构
C.索引存取的顺序结构
D.散列存取的顺序结构

A。存取方式指的是读写方式,顺序表是一种支持随机存取(在计算机科学中,随机存取(有时亦称直接访问)代表同一时间访问一组序列中的一个随意组件。)的存储结构。

三、链表

3.1单链表

3.1.1单链表的定义

3.1.1.1定义及初始化
//链表的定义
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
} LNode,*LinkList;

//初始化空的单链表
bool InitList(LinkList &L)
{
    L=NULL;         //防止脏数据
    return true;
}
/ / 判断表空
bool Empty(LinkList L)
{
    return (L==NULL);
}

//初始化带头结点的单链表
bool InitList(LinkList &L)
{
    L=(LNode *)malloc(sizeof(LNode));
    if(L==NULL)
        return false; //内存不足分配失败
    L->next=NULL;
    return true;
}
//判断表空
bool Empty(LinkList L)
{
    if(L->next==NULL)
        return false;
    return true;
}

LinkList 强调这是一个单链表
LNode * 强调这是一个结点

3.1.1.2小结

在这里插入图片描述

3.1.2单链表的插入

3.1.2.1按位序插入
//按位序插入(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
    if(i<1)
        return false;
    LNode *p;       //p指针指向当前扫描到的结点
    int j=0;        //p当前指向的是第几个结点
    p=L;            //L指向第0个结点,是头结点
    while(p!=NULL&&j<i-1) //循环找到第i-1个结点
    {
        p=p->next;
        j++;
    }
    if(p==NULL)     //i的值不合法
        return false;
    LNode *s=(LNode *)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
}
//按位序插入(不带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
    if(i<1)
        return false;
    if(i==1)        //插入第一个结点操作略有不同
    {
        LNode *s=(LNode *)malloc(sizeof(LNode));
        s->data=e;
        s->next=L;
        L=s;
        return true;
    }
    LNode *p;       //p指针指向当前扫描到的结点
    int j=1;        //p当前指向的是第几个结点
    p=L;            //L指向第1个结点,不是头结点!!
    //与带头结点一样
    while(p!=NULL&&j<i-1) //循环找到第i-1个结点
    {
        p=p->next;
        j++;
    }
    if(p==NULL)     //i的值不合法
        return false;
    LNode *s=(LNode *)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
}

带头结点的插入要注意,插入第一个要单独区别

3.1.2.2指定结点的后插
//指定结点的后插
bool InsertNextNode(LNode *p,ElemType e){
    if(p==NULL)
        return false;
    LNode *s=(LNode *)malloc(sizeof(LNode));
    if(s==NULL)         //内存分配失败
        return false;
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
} 

对3.1.2.1按位序插入中带头和不带头的相同代码部分进行封装如下:

//按位序插入(带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
    if(i<1)
        return false;
    LNode *p;       //p指针指向当前扫描到的结点
    int j=0;        //p当前指向的是第几个结点
    p=L;            //L指向第0个结点,是头结点
    while(p!=NULL&&j<i-1) //循环找到第i-1个结点
    {
        p=p->next;
        j++;
    }
    return InsertNextNode(p,e);
}
//按位序插入(不带头结点)
bool ListInsert(LinkList &L,int i,ElemType e)
{
    if(i<1)
        return false;
    if(i==1)        //插入第一个结点操作略有不同
    {
        LNode *s=(LNode *)malloc(sizeof(LNode));
        s->data=e;
        s->next=L;
        L=s;
        return true;
    }
    LNode *p;       //p指针指向当前扫描到的结点
    int j=1;        //p当前指向的是第几个结点
    p=L;            //L指向第1个结点,不是头结点!!
    //与带头结点一样
    while(p!=NULL&&j<i-1) //循环找到第i-1个结点
    {
        p=p->next;
        j++;
    }
    return InsertNextNode(p,e);
}
3.1.2.3指定结点的前插
//指定结点的前插
bool InsertPriorNode(LNode *p,ElemType)
{
    if(p==NULL)
        return false;
    LNode *s=(LNode *)malloc(sizeof(LNode));
    if(s==NULL)
        return false;
    s->next=p->next;
    p->next=s;
    s->data=p->data;
    p->data=e;
    return true;
}

3.1.3单链表的删除

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

如果p是最后一个结点,只能从表头依次往后查找前驱节点,体现了单链表的局限性,无法逆向检索

3.1.3.3小结

在这里插入图片描述

3.1.4单链表的查找

其实在上面的插入和删除中已经涵盖了相关代码

3.1.4.1按位查找
//按位查找(带头结点)
LNode * GetElem(LinkList L,int i)
{
    if(i<0)
        return false;
    LNode *p;
    int j=0;
    p=L;
    while(p!=NULL&&j<i)
    {
        p=p->next;
        j++;
    }
    return p;
}

可以用该函数把删除和插入中对i-1结点的查找替换为LNode * GetEle(L,i-1);

3.1.4.2按值查找
//按值查找(带头)
LNode * locateElem(LinkList L,ElemType e)
{
    LNode *p=L->next;
    while(p!=NULL&&p->data!=e)
        p=p->next;
    return p;
}

3.1.5求表长

//求表长(带头结点)
int length(LinkList L)
{
    int len=0;
    LNode *p=L;
    while(p->next!=NULL)
    {
        p=p->next;
        len++;
    }
    return len;
}

3.1.4-3.1.5小结

在这里插入图片描述

3.1.6单链表的建立

3.1.6.1尾插法
//尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
    int x;
    L=(LinkList)malloc(sizeof(LNode));
    LNode *s,*r=L;      //r为表尾指针
    scanf("%d",&x);
    while(x!=9999)      //设置一个结束值
    {
        s=(LNode *)malloc(sizeof(LNode));
        s->data=x;
        r->next=s;
        r=s;
        scanf("%d",&x);
    }
    r->next=NULL;
    return L;
}
3.1.6.2头插法

理解为对头结点进行后插法

//头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
    int x;
    LNode *s;
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;       //初始为空链表
    scanf("%d",&x);
    while(x!=9999)      //设置一个结束值
    {
        s=(LNode *)malloc(sizeof(LNode));
        s->data=x;
        s->next=L->next;
        L->next=s;
        scanf("%d",&x);
    }
    return L;
}

重点应用:链表的逆置

3.2双链表

两个指针priornext

3.2.1定义及初始化

3.2.1.1定义
//定义双链表
typedef struct Dnode
{
    ElemType data;
    struct Dnode *prior,*next;
} DNode,*DLinkList;
3.2.1.2初始化
//初始化双链表
bool InitDLinkList(DLinkList &L)
{
    L=(DNode *)malloc(sizeof(DNode));
    if(L==NULL)
        return false;
    L->prior=NULL;  //头结点的prior永远指向NULL
    L->next=NULL;
    return true;
}

3.2.2插入

//p结点后插入s结点
bool InsertNextDNode(DNode *p,DNode *s)
{
    if(p==NULL||s==NULL)
        return false;
    s->next=p->next;
    if(p->next!=NULL)
        p->next->prior=s;
    s->prior=p;
    p->next=s;
    return true;
}

3.2.3删除

//删除p的后继结点
bool DeleteNextDNode(DNode *p)
{
    if(p==NULL)
        return false;
    DNode *q=p->next;
    if(q==NULL)
        return false;
    p->next=q->next;
    if(q->next!=NULL)
        q->next->prior=p;
    free(q);
    return true;
}

3.2.4小结

在这里插入图片描述

3.3循环链表

3.3.1初始化循环单链表

//循环单链表的初始化
bool InitList(LinkList &L)
{
    L=(LNode *)malloc(sizeof(LNode));
    if(L==NULL)
        return false;
    L->next=L;      //头结点的next指针指向头结点
    return true;
}
//判断空表
bool Empty(LinkList L)
{
    if(L->next==L)
        return true;
    return false;
}

3.3.2初始化循环双链表

//循环双链表的初始化
bool InitDLinkList(DLinkList &L)
{
    L=(DNode *)malloc(sizeof(DNode));
    if(L==NULL)
        return false;
    L->prior=L;
    L->next=L;
    return true;
}
//判断空表
bool Empty(DLinkList L)
{
    if(L->next=L)
        return true;
    return false;
}

3.3.3小结

在这里插入图片描述

3.4静态链表

3.4.1定义

//静态链表的定义
#define MaxSize 10
typedef struct
{
    ElemType data;
    int next;
} SLinkList[MaxSize];

四、顺序表和链表比较

在这里插入图片描述

五、写在最后

付出,才有收获!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

森格的博

创作不易,感谢支持

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

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

打赏作者

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

抵扣说明:

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

余额充值