顺序表的基操

L线性表

线性结构

线性结构的基本特点就是,除了第一个元素无直接前驱以及最后一个元素无直接后续以外,其他所有元素都有一个前驱和后继。并且线性表是最基本的一种线性结构

线性表的定义

ADT List{
    数据对象: ....
    数据关系: ....
    基本操作: ....
}ADT List

顺序表

顺序存储方法:用一组地址连续的存储单元依次存储线性表的元素,可通过**数组V[n]**来实现。

顺序表的类型定义

#define MAXSIZE 100
typedef struct{
    ElemType *elem;  //指向数据元素的基地址
    int length;      //线性表的当前长度  
}SqList;

顺序表的基本实现

初始化线性表L(参数用引用的方式)
typedef int Status;//用于返回构造顺序表的一个结果类型
Status InitList_Sq(Sqlist &L) //一个构造顺序表的函数方法,函数名为InitList_Sq,返回值类型为Status
{
    L.elem = new ElemType[MAXSIZE];//为顺序表分配空间
    if(!L.elem)
        exit(OVERFLOW);//分配失败,退出程序
    //分配成功继续运行
    L.length=0;//表长为0
    return OK;
}
初始化线性表(参数用指针的方式)
typedef int Status;
Status InitList_Sq(SqList *L)
{
    L->elem = new ElemType[MAXSIZE];
    if(!L->elem)
        exit(OVERFLOW);
    L->length=0;
    return OK;
}
销毁线性表L
void DestoryList(SqList &L)
{
    if(L.elem)
        delete[]L.elem;//回收指针空间;
}
清空线性表L
void ClearList(SqList &L)
{
    L.length=0; //将线性表的表长重置为0
}
求线性表L的长度
int GetLength(SqList L)//因为只要对线性表的长度进行一个获取,不需要对表本身进行任何操作,所以不需要进行将参数进行引用处理
{
    return L.length;
}
判断线性表L是否为空
int IsEmpty(SqList L)
{
    if(L.length==0)
        return 1;
    return 0;
}
获取线性表L中的某个数据元素的内容
#define OK 1
#define ERROR 0
//根据指定位置,获取相应位置数据元素的内容
int GetElem(SqList L,int i,ElemType &e)
{
    if(i<1||i>L.length) //先判断查找位置是否存在
        return ERROR;
    e = L.elem[i-1] //因为数组是从0开始的,所以第i个位置对应于数组第i-1个元素
        return OK;
}
在线性表L中查找值为e的数据元素
int LocateElem(SqList L,ElemType e)
{
    for(int i=0;i<L.length;i++)
    {
        if(L.elem[i] == e)
        return i+1;
    }
    return 0;
}
在线性表中指定位置前插入一个元素

在一个长度为n的线性表插入一个元素后,就变成了长度为n+1的线性表

就需要将第i至第n共**(n-i+1)**个元素后移。

并且在进行数组操作的时候要从最后一个元素开始移动

首先我们要判断以下几个问题

(1)判断插入位置i是否合法

(2)判断顺序表的存储空间是否已满

(3)将第n至第i位的元素依次向后移动一个位置,空出第i个位置。

(4)将要插入的新元素e放入第i个位置

(5)表长加1,插入成功返回OK。

typedef int Status;
#define OK 1
#define ERROR 0
#define MAXSIZE 100
Status ListInsert_Sq(SqList &L,int i,ElemType e)
{
    if(i<1||i>L.length+1)//插入位置可以是最后一个元素的后面也就是i+1这个位置。
        return ERROR;
    if(L.length==MAXSIZE)//判断存储空间是否满
        return ERROR;
    for(j=L.length-1;j>=i-1;j--)
    {
        L.elem[j+1]=L.elem[j];
    }
    L.elem[i-1]=e;
    L.length++;
    return OK;
}
对于对应位置的删除操作

ListDelete(&L,i,&e)

其中要删除第i个位置上的元素,则其后元素共n-i个元素要从前往后移。

(1)判断删除位置i是否合法。(合法值为1<=i<=n)

(2)将欲删除的元素保留在e中。

(3)将第i+1至第n位的元素依次向前移动一个位置。

(4)表长减1,删除成功返回OK

Status ListDelete_Sq(SqList &L,int i,ElemType &e)
{
    if(i<1||i>L.length)//判断位置是否合法
    {
        return ERROR;
    }
    e=L.elem[i-1];//将删除的值赋予e,达到一个返回的作用。
    for(j=i;j<=L.length-1;j++)
    {
        L.elem[j-1]=L.elem[j];
    }
    L.length--;
    return OK;
}

线性表的优缺点

优点

存储密度大

可以随机存取表中任一元素

缺点

在插入、删除某一元素时,需要移动大量元素

浪费存储空间

属于静态存储形式,数据元素的个数不能自由扩充

链表

节点的组成

各结点由两个域组成

数据域存储元素数值数据
指针域存储直接后继结点的存储位置

链表分类

单链表:结点只有一个指针域的链表,称为单链表或者线性链表。

双链表:有两个指针域的链表,称为双链表。

循环链表:首尾相接的链表称为循环链表。

头指针、头结点和首元结点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I5duBz1w-1632402892852)(C:\Users\Lenovo\Desktop%9BQ}X3E@6$0]C_3XV_7UEB.jpg)]

头指针:是指向链表中第一个结点的指针。

首元结点:是指链表中存储第一个数据元素a1的结点。

头结点:是在链表的首元结点之前附设的一个结点;数据域内只存放空表标志和表长等信息。

在链表中设置头结点的好处

1.便于首元结点的处理:

首元结点的地址保存在头结点的指针域中,所以在链表中的第一个位置上的操作和其它位置一致,无须进行特殊处理。

2.便于空表和非空表的统一处理

无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就是统一了。

链表的优缺点

优点

1.数据元素的个数可以自由扩充。

2.插入、删除等操作不必移动数据,只需修改链接指针,修改效率较高。

缺点

1.存储密度小。

2.存取效率不高,必须采用顺序存取,即存取数据元素时,只能按链表的顺序进行访问。

单链表的定义和实现

单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名。

若头指针名是L,则把链表称为表L。

typedef struct LNode{
    ElemType data;//数据域
    struct LNode *next;//指针域
}LNode,*LinkList;
//*LinkList 为LNode类型的指针
//其中 LNode *p 和 LinkList p 是等价的

单链表基本操作的实现

初始化(构造一个空表)

算法分析:生成新结点作为头结点,用头指针L指向头结点。

​ 头结点的指针域置空。

typedef int Status;
Status InitList_L(LinkList &L)
{
    L=new LNode; //生成头结点
    L->next=NULL;
    return OK;
}
销毁操作
Status DestoryList_L(LinkList &L)
{
    LinkList p;
    while(L)
    {
        p=L;
        L=L->next;
        delete p;
    }
    return OK;
}
清空链表
Status ClearList(LinkList &L)
{
    LinkList p,q;
    p=L->next;//p指向首元结点
    while(p)//p指针非空,可以继续进行操作。
    {
        q=p->next;
        delete p;
        p=q;
    }
    L->next=NULL;//将头结点指针域设置为空
    return OK;
}
求表长
int ListLength_L(LinkList L)
{
    LinkList p;
    p=L->next;
    int i=0;
    while(p)
    {
        i++;
        p=p->next;
    }
    return i;
}
判断链表是否为空
int ListEmpty(LinkList L)
{
    if(L->next)
        return 0;//为非空
    else
        return 1;//为空
}
查找操作
按照序号进行查找

Get(L,i,&e)

查找在链表L中第i个元素的值,如果找到,将其赋值给e进行返回操作。

Status GetElem_L(LinkList L,int i,ElemType &e)
{
    LinkList p;
    p=L->next;
    j=1;
    while(p&&j<i)
    {
        p=p->next;
        j++;
    }
    if(!p||j>i)
        return ERROR;
    else
    {
        e=p->data;
        return OK;
    }
}
按照值进行查找
LNode *LocateElem_L(LinkList L,Elemtype e)
{
    LinkList p;
    p=L->next;
    while(p&&p->data!=e)
    {
        p=p->next;
    }
    return p;//如果找到就返回p指针,如果没有找到的返回值就为NULL
}
插入操作

案例:将s节点插入到ai节点前,则需要将p指针移动到ai-1节点的位置进行操作。

//在L中第i个元素之前插入数据元素e
Status ListInsert_L(LinkList &L,int i,ElemType e)
{
    LinkList p;
    p=L;
    int j=0;
    while(p&&j<i-1)//寻找i-1个节点,所以p指针要在头结点的位置,而不是首元结点。
    {
        j++;
        p=p->next;
    }
    if(!p||j>i-1)//i的位置为非法位置,无法进行寻找
        return ERROR;
    s=new LNode;
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}//让新节点s和第i个位置的节点建立联系,然后让第i-1个节点和新节点s建立联系,并同时把第i-1个节点和第i个节点之前的联系断开。
删除操作
Status ListDelete_L(LinkList &L,int i,ElemType &e)
{
    LinkList p;
    p=L;
    int j=0;
    while(p->next&&j<i-1)//寻找第i-1个结点,并且令p指向其前驱结点
    {
        p=p->next;
        j++;
    }
    if(!(p->next)||j>i-1)//要删除的位置i非法
        return ERROR;
    LinkList q;
    q=p->next;
    p->next=q->next;
    e=q->data;
    delete q;
    return OK;
}

单链表的建立

前插法

创建一个空表

生成新结点

将读入的数据存放到新结点的数据域中

将该新结点插入到链表的前端(头结点的后面)

void CreatList_F(LinkList &L,int n)
{
    L=new LNode;
    L->next=NULL;
    for(int i=n;i>0;i--)
    {
        p=new LNode;
        cin>>>p->data;
        p->next=L->next;
        L->next=p;
    }
}
尾插法
void CreatList_L(LinkList &L,int n)
{
    L=new LNode;
    L->next=NULL;
    r=L;
    for(int i=0;i<n;i++)
    {
        p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;//插入到表尾
        r=p;//将r指向新的表尾
    }
}

两个循环链表的合并操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1GmrlDUX-1632402892872)(C:\Users\Lenovo\Desktop\QQ图片20210923172916.jpg)]

LinkList *CONNECT(LinkList *ra,LinkList *rb)
{
    LinkList *p;
    p=ra->next;
    ra->next=rb->next->next;
    free(rb->next);
    rb->next=p;
    return rb;
}

双向链表

创建格式
typedef struct DulNode{
    ElemType data;
    struct DulNode *prior;
    struct DulNode *next;
}DulNode,*DuLinkList;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8YNYAIpj-1632402892880)(C:\Users\Lenovo\Desktop\QQ图片20210923183859.jpg)]

Status ListInsert_DuL(DuLinkList &L,int i,ElemType e)
{
    if(!(p=GetElemP_Dul(L,i)))//查找是否存在第i个值在L表中
        return ERROR;
    s=new DuLNode;
    s->data=e;
    s->prior=p->prior;
    p->prior->next=s;
    s->next=p;
    p->prior=s;
    return OK;
}
双向链表的删除

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mvvpUcXn-1632402892885)(C:\Users\Lenovo\Desktop\QQ图片20210923185525.jpg)]

Status ListDelete_Dul(DuLinkList &L,int i,ElemType &e)
{
    if(!(p=GetElemP_Dul(L,i)))
        return ERROR;
    e=p->data;
    p->prior->next=p->next;
    p->next->prior=p->prior;
    delete p;
    return OK;
}

线性表的应用

无序线性表的合并

利用顺序表进行操作
#include<iostream>
#include<windows.h>
using namespace std;
#define MAXSIZE 100
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct
{
    ElemType * elem;
    int Length;
}SqList;

Status InitList(SqList &L)
{
    L.elem = new ElemType[MAXSIZE];
    if(!L.elem)
        return ERROR;
    else
    {  L.Length=0;
        return OK;
    }
}

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

void Creat_List(SqList &L)
{
    int n;
    cout<<"请输入要顺序表的元素个数"<<endl;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cout<<"请输入第"<<i+1<<"个元素的值为: ";
        cin>>L.elem[i];
        L.Length++;
    }

}

void Combine(SqList &La,SqList &Lb)
{
    for(int i=0;i<Lb.Length;i++)
    {
        int flag=0;
        for(int j=0;j<La.Length;j++)
        {
            if(La.elem[j]==Lb.elem[i])
            {
                flag++;
            }
        }
        if(!flag)
        {
            La.elem[La.Length++]=Lb.elem[i];
        }
    }
}

void TravelList(SqList &L)
{
    cout<<"顺序表的值为:";
    for(int i=0;i<L.Length;i++)
    {
        cout<<L.elem[i]<<" ";
    }
}

int main()
{
    SqList A,B;
    if(InitList(A))
    {
        cout<<"顺序表A初始化成功!"<<endl;
        Creat_List(A);
        TravelList(A);
    }
    else
    {
        cout<<"顺序表A初始化失败!"<<endl;
        exit(0);
    }
    if(InitList(B))
    {
        cout<<"顺序表B初始化成功!"<<endl;
        Creat_List(B);
        TravelList(B);
    }
    else
    {
        cout<<"顺序表B初始化失败!"<<endl;
        exit(0);
    }
    Sleep(100);
    cout<<endl<<"正在将A和B顺序表进行结合!!!"<<endl;
    Combine(A,B);
    cout<<"结合后的表长为"<<A.Length<<endl;
    TravelList(A);
}

进行有序的线性表的合并

利用顺序表操作

要求:已知线性表La和Lb中的数据元素按值非递增有序排列,现要求将La和Lb归为一个新的线性表Lc,且Lc中的数据元素扔按值非递增有序排列。

#include<iostream>
using namespace std;
#define ERROR 0
#define OK 1
#define MAXSIZE 100
typedef int Status;
typedef int ElemType;
int x=0;
typedef struct
{
    ElemType *elem;
    int length;
}SqList;

Status InitList(SqList &L)
{
    L.elem = new ElemType[MAXSIZE];
    if(!L.elem)
        return ERROR;
    else
    {
        L.length=0;
        return OK;
    }

}

int LengthList(SqList &L)
{
    return L.length;
}

void CreatList(SqList &L)
{
    int n;
    cout<<"请输入第"<<x+1<<"个顺序表的元素个数"<<endl;
    x++;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cout<<"顺序表第"<<i+1<<"个值为:";
        cin>>L.elem[i];
        L.length++;
    }
}

void TravelList(SqList &L)
{
    cout<<"顺序表的值为:";
    for(int i=0;i<L.length;i++)
    {
        cout<<L.elem[i]<<" ";
    }
}

void Union(SqList La, SqList Lb,SqList &Lc)
{
    ElemType *pa = La.elem;
    ElemType *pb = Lb.elem;
    Lc.length=La.length+Lb.length;
    Lc.elem = new ElemType[Lc.length];
    ElemType *pc = Lc.elem;
    ElemType *pa_last=La.elem+La.length-1;
    ElemType *pb_last=Lb.elem+Lb.length-1;
    while(pa<=pa_last&&pb<=pb_last)
    {
        if(*pa<=*pb)
        {
            *pc++=*pb++;
        }
        else
        {
            *pc++=*pa++;
        }
    }
    while(pa<=pa_last)
    {
        *pc++=*pa++;
    }
    while(pb<=pb_last)
    {
        *pc++=*pb++;
    }

}
int main()
{
       SqList A,B;
       if(InitList(A))
       {
           cout<<"顺序表A初始化成功!"<<endl;
           CreatList(A);
           TravelList(A);
       }
       else
       {
           cout<<"顺序表初始化失败!"<<endl;
           exit(0);
       }
       if(InitList(B))
       {
           cout<<"顺序表B初始化成功!"<<endl;
           CreatList(B);
           TravelList(B);
       }
       else
       {
           cout<<"顺序表初始化失败"<<endl;
           exit(0);
       }
       SqList C;
       Union(A,B,C);
       cout<<"顺序表C的表长为"<<C.length<<endl;
       TravelList(C);
       return 0;
}
利用链表操作进行有序的线性表合并
#include<iostream>
using namespace std;
#define ERROR 0
#define OK 1
typedef int Status;
typedef int ElemType;

typedef struct LNode
{
    ElemType data;
    struct LNode * next;
}LNode,*LinkList;

Status InitList(LinkList &L)
{
    L = new LNode;
    L->next=NULL;
    return OK;
}

void CreatList(LinkList &L)
{
    int n;
    cout<<"请输入要插入的结点数目:";
    cin>>n;
    LinkList p;
    for(int i=0;i<n;i++)
    {
        p = new LNode;
        cout<<"请输入第"<<i+1<<"个结点的值:";
        cin>>p->data;
        p->next=L->next;
        L->next=p;
    }
}

void TravelList(LinkList &L)
{
    int i=0;
    LinkList p;
    p=L->next;
    while(p)
    {
        if(!i){
            cout<<"链表的值为:";
         i++;
        }
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}

void MergeList(LinkList &la,LinkList &lb,LinkList &lc)
{
    cout<<"进行有序链表排序"<<endl;
    LinkList pa,pb,pc;
    pa = la->next;
    pb = lb->next;
    pc=lc=la;
    while(pa&&pb)
    {
        if(pa->data<=pb->data)
        {
            pc->next=pa;
            pc=pa;
            pa=pa->next;
        }
        else
        {
            pc->next=pb;
            pc=pb;
            pb=pb->next;
        }
    }

    pc->next=pa?pa:pb;
    delete lb;
}
int main()
{LinkList A,B,C;

if(InitList(A))
{
    cout<<"链表A初始化成功!"<<endl;
    CreatList(A);
    TravelList(A);
}
else
{
    cout<<"链表初始化失败!"<<endl;
}
if(InitList(B))
{
    cout<<"链表B初始化成功!"<<endl;
    CreatList(B);
    TravelList(B);
}
else
{
    cout<<"链表初始化失败!"<<endl;
}
if(InitList(C))
{
    cout<<"链表C初始化成功!"<<endl;

}
else
{
    cout<<"链表初始化失败!"<<endl;
}

MergeList(A,B,C);
TravelList(C);
return 0;

}

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值