【线性表】顺序存储、链式存储的实现及操作

一、线性表的定义:

(1)概念定义:用数据元素的有限序列表示叫做线性表;线性表中数据元素的类型可以为简单类型,也可以为复杂类型。许多实际应用问题所涉的基本操作有很大相似性,不应为每个具体应用单独编写一个程序。从具体应用中抽象出共性的逻辑结构和基本操作(抽象数据类型),然后实现其存储结构和基本操作。

(2)类型定义:首先抽象出ADT List表的结构,在C/C++中一般都是采用struct来实现的。基本操作有如下:InitList(&L):创建一个新表;DestroyList(&L):销毁一个线性表;ClearList(&L):清空表;ListEmpty(L):判断表是否为空;ListLength(L):求表的长度;GetElem(L,i,&e):读取表的元素;LocateElem(L,e):查找表的元素; PriorElem(L,cur_ e,&pre _e):求表的前驱;NextElem(L,cur_ e,&next_e) :求表的后继;ListInsert(&L,i,e) :前插表;ListDelete(&L,i,&e):删除表;TraverseList (L):遍历表;

二、线性表的顺序表示和实现

(1)概念:线性表的顺序表示又称为顺序存储结构或顺序映像。顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。逻辑上相邻,物理上也相邻;用一组地址连续的存储单元依次存储线性表的元素,可通过数组V[n]来实现。

(2)实现:下面是具体代码的大概实现;
# include <iostream>
using namespace std;

# define OK 1
# define ERROR 0
# define OVERFLOW -2
# define MAXSIZE 100
typedef int ElemType;
typedef int Status;

typedef struct{
    ElemType *elem;
    int length;
}SqList;

Status InitList_Sq(SqList &L){//创建一个空的顺序表L
    L.elem = new ElemType[MAXSIZE];
    if(!L.elem)
        exit(OVERFLOW);
    L.length = 0;
    return OK;
}

void DestoryList_Sq(SqList &L){//销毁线性表L
    if(L.elem)
        delete[]L.elem;//释放存储空间
}

void ClearList_Sq(SqList &L){//清空线性表L
    L.length = 0;
}

int GetLength_Sq(SqList &L){//求线性表L的长度
    return (L.length);
}

int IsEmpty_Sq(SqList L){//判断线性表为空
    if(L.length == 0)
        return 1;
    else
        return 0;
}

Status GetElem_Sq(SqList L,int i,ElemType &e){//获取元素
    if(i<1 || i>L.length)  //判断i值是否合理,若不合理,返回ERROR
        return ERROR;  
    e = L.elem[i-1];       ////第i-1的单元存储着第i个数据
    return OK;
}

int LocateElem_Sq(SqList L,ElemType e){//查找元素
    for(int i=0; i<L.length; i++){
        if(L.elem[i] == e)
            return i+1;  //查找的元素实际上是在第i+1个位置
    }
    return 0;
}

Status InsertElem_Sq(SqList &L,int i,ElemType e){
    if(i<1 || i>L.length+1)
        return ERROR;     //插入位置的i值不合法
    if(L.length == MAXSIZE)
        return ERROR;     //当前的存储空间已满
    for(int j=L.length-1; j>=i-1; j--){
       L.elem[j+1] = L.elem[j];    //插入位置及之后的元素后移
    }
       L.elem[i-1] = e;            //将新元素e放入第i个位置
       ++L.length;                 //表长增加1
    return OK;
}

Status DeleteElem_Sq(SqList &L,int i){
    if(i<1 || i>L.length)
        return ERROR;              //删除位置不合法
    for(int j=i;j<=L.length-1;j++){
        L.elem[j-1] = L.elem[j];   //被删除元素之后的元素前移 
    }
    --L.length;                    //表长减少1
    return OK;
}

void print(SqList L){
    for(int i=0;i<L.length;i++){
        cout<<L.elem[i]<<endl;
    }
}

int main(){
    SqList lst;
    InitList_Sq(lst);
    int i,n;
    ElemType e; 
    cout<<"请输入顺序表的长度:"<<endl;
    cin>>n;
    for(i=1;i<=n;i++){
        cout<<"请输入第"<<i<<"个元素:"<<endl;
        cin>>e;
        InsertElem_Sq(lst,i,e);
    }
    print(lst);
    cout<<"请问要删除第几个元素:"<<endl;
    cin>>i;
    DeleteElem_Sq(lst,i);
    print(lst);
    cout<<"要在第几个位置插入元素?"<<endl;
    cin>>i;
    cout<<"需要插入的元素是?"<<endl;
    cin>>e;
    InsertElem_Sq(lst,i,e);
    print(lst);
    cout<<"请问需要取第几个元素?"<<endl;
    cin>>i;
    GetElem_Sq(lst,i,e);
    cout<<"第"<<i<<"个元素是"<<e<<endl<<endl;
    cout<<"要查询哪个元素?"<<endl;
    cin>>e;
    n = LocateElem_Sq(lst,e);
    if(n!=0)
        cout<<"成功找到元素,在第"<<n<<"个位置"<<endl;
    else
        printf("没有找到该元素\n");
    cout<<"现在清空线性表!"<<endl;
    ClearList_Sq(lst);
    printf("线性表长度为:%d\n",GetLength_Sq(lst));
    return 0;
}

三、线性表的链式表示和实现

(1)概念:链式存储结构,结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻;与上面提到的顺序存储不同,链式存储在计算机内存中的表示是随机的,它只是在逻辑是相邻的,物理是不相邻;线性表的链式表示又称为非顺序映像或链式映像;链表是通过指针来进行实现的;

(2)链表的相关术语:链表是通过每个结点连接在一起来实现的,所以每个结点都由两个域组成。一、数据域:存储元素数值数据;二、指针域:存储直接后继结点的存储位置;所以由许多个结点组成的表就叫链表。链表中还有头指针,头结点,首元结点。头指针是指向链表中第一个结点的指针,首元结点是指链表中存储第一个数据元素a1的结点,头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息。

(3)链表的分类:结点只有一个指针域的链表,称为单链表或线性链表;有两个指针域的链表,称为双链表;首尾相接的链表称为循环链表;

四、单链表的定义和实现 ##

(1)概念:单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名;若头指针名是L,则把链表称为表L;

(2)下面用代码介绍单链表的基本操作和实现:
# include <stdio.h>
# include <stdlib.h>
# include <iostream>
using namespace std;
# define OK 1
# define ERROR 0
typedef int ElemType;
typedef int Status;

typedef struct LNode{
    ElemType data;      //数据域
    struct LNode *next; //指针域
}LNode,*LinkList;       // *LinkList为LNode类型的指针

Status InitList_L(LinkList &L){//构造一个空表
    L = new LNode;
    L->next = NULL;
    return OK;
}

Status DestroyList_L(LinkList &L){//销毁表
    LinkList p;
    while(L){
        p=L;  
        L=L->next;
        delete p;  
    }
    return OK;
}

Status ClearList_L(LinkList &L){//清空表
    LinkList p,q;
    p=L->next;   //p指向第一个结点
    while(p)     //没到表尾 
    {    
        q=p->next; 
        delete p;     
        p=q;   
     }
    L->next=NULL;   //头结点指针域为空 
    return OK;
}

int ListLength_L(LinkList L){//返回L中数据元素个数
    LinkList p;
    p=L->next;  //p指向第一个结点
    int i=0;        //设置计数变量i          
    while(p){   //遍历单链表,统计结点数
        i++;
        p=p->next;
    } 
    return i;
}


int IsEmpty_L(LinkList L){ //判断表是否为空,如果是返回1,非空返回0
    if(L->next) 
        return 0;
    else
        return 1;
 }

Status GetElem_L(LinkList L,int i,ElemType &e){//获取线性表L中的第i个数据元素的内容
    LinkList p;
    p=L->next;
    int j=1;       //初始化
    while(p&&j<i){ //向后扫描,直到p指向第i个元素或p为空 
        p=p->next; 
        ++j; 
    } 
    if(!p || j>i)
        return ERROR;  //第i个元素不存在 
    e=p->data;         //取第i个元素 
    return OK; 
}


int LocateELem_L (LinkList &L,ElemType e) {
 //返回L中值为e的数据元素的位置序号,查找失败返回0
    LinkList p;
    p=L->next; 
    int j=1;
    while(p != NULL){
        if(p->data != e){
            ++j;
            p=p->next;
        }
        else
            break;
    }
    return j--;
} 


Status ListInsert_L(LinkList &L,int i,ElemType e){//在L表中第i个位置插入e元素
    LinkList p,s;
    p=L;
    int j=0;
    while(p && j<i-1){//寻找第i-1个结点
        p = p->next;   
        ++j;
    }
    if(!p || j>i-1)
        return ERROR;
    s=new LNode;     //生成新结点s 
    s->data=e;       //将结点s的数据域置为e 
    s->next=p->next; //将结点s插入L中 
    p->next=s; 
    return OK; 
}

Status ListDelete_L(LinkList &L,int i,ElemType &e){将线性表L中第i个数据元素删除
    LinkList p,q;
    p=L;
    int j=0; 
    while(p->next && j<i-1){//寻找第i个结点,并令p指向其前驱 
        p=p->next; 
        ++j; 
    } 
    if(!(p->next) || j>i-1) 
        return ERROR;       //删除位置不合理 
    q=p->next;              //临时保存被删结点的地址以备释放 
    p->next=q->next;        //改变删除结点前驱结点的指针域 
    e=q->data;              //保存删除结点的数据域 
    delete q;               //释放删除结点的空间 
    return OK; 
}

Status print(LinkList L){
    LinkList p;
    p = L->next;
    while(p != NULL){
        cout<<p->data<<endl;
        p = p->next;
    }
    return OK;
}

int main(){
    int i,n;
    ElemType e;
    LinkList L;
    InitList_L(L);
    cout<<"请输入链表的长度:"<<endl;
    cin>>n;
    for(i=1; i<=n;i++){
        cout<<"请输入第"<<i<<"个元素:"<<endl;
        cin>>e;
        ListInsert_L(L,i,e);
    }
    n = ListLength_L(L);
    cout<<"插入完毕,表的长度是:"<<n<<endl;
    printf("\n");
    if(IsEmpty_L(L) == 0)
        cout<<"表不为空,内容是:"<<endl;
    print(L);
    cout<<"请输入你要查找的元素:"<<endl;
    cin>>e;
    n = LocateELem_L(L,e);
    if(n != 0)
        cout<<"查找成功,元素在第"<<n<<"个位置"<<endl;
    else
        cout<<"查找失败,没有找到元素"<<endl;
    printf("\n");
    cout<<"请问你想删除第几个元素:"<<endl;
    cin>>i;
    ListDelete_L(L,i,e);
    cout<<"元素删除成功!"<<endl;
    print(L);
    printf("\n");
    cout<<"请问你想获取哪个位置的元素?"<<endl;
    cin>>i;
    GetElem_L(L,i,e);
    cout<<"获取成功,第"<<i<<"个位置的元素是:"<<e<<endl;
    cout<<"操作结束,现在清空链表!"<<endl;
    ClearList_L(L);
    n = ListLength_L(L);
    cout<<"清空完毕,链表的长度为:"<<n<<endl;
    DestroyList_L(L);

    /*  查找:  因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为 O(n)。
        插入、删除:  因线性链表不需要移动元素,只要修改指针,一般情况下时间复杂度为 O(1)。
        但是,如果要在单链表中进行前插或删除操作,由于要从头查找前驱结点,所耗时间复杂度为 O(n) 。
    */

    return 0;
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值