数据结构 - 线性表

ADT 线性表(List)
Data
    线性表的数据对象集合为{a1,a2,......,an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素都有一个直接前驱元素,除了最后一个元素an外,每一个元素都有一个直接后继元素。数据元素直接的关系是一对一的关系。
Operation
    InitList(*L) :   初始化操作,建立一个空的线性表。
    ListEmpty(L) :   若线性表为空,返回true,否则返回false。
    ClearList(*L) :    将线性表清空。
    GetElem(L,i,*e) :  将线性表L中的第i个位置元素值返回给e。
    LocateElem(L,e) :  在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号以表示成功;否则,返回0表示失败。
    ListInsert(*L,i,e)  :    在线性表L中的第i个位置插入新元素e。
    ListDelete(*L,i,*e) :    删除线性表L中第i个位置元素,并用e返回其值。
    ListLength(L) :          返回线性表L的元素个数。
endADT

一、线性表的顺序存储结构

线性表的顺序存储结构

线性表的顺序存储结构2

线性表的顺序存储的结构代码:

#include <stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20    
                      /*存储空间初始分配量*/
typedef int Status;   /*Status是函数的类型,其值是函数结果状态代码,如OK等*/
typedef int ElemType; /*ElemType类型根据实际情况而定,这里假设为int*/
typedef struct
{
    ElemType data[MAXSIZE]; /*数组存储数据元素,最大值为MAXSIZE*/
    int length;              /*线性表当前长度*/ 
}SqList;

顺序线性表的初始化操作代码:

/* 初始条件:顺序线性表L不存在。 */
/* 操作结果:生成顺序线性空表L。 */
Status InitList (SqList *L)
{
    L = (SqList *)malloc(sizeof(SqList));
    if (!L)
    {
        exit(0);
        return ERROR;
    }
    L->length = 0;
    return OK;
}

判断顺序线性表是否为空操作的代码:

/* 初始条件:顺序线性表L已存在。*/
/* 操作结果:返回判断的值      */
Status ListEmpty (SqList L)
{
    if (L.length == 0)
        return TRUE;
    else 
        return FALSE;
}

顺序线性表清空操作的代码:

/* 初始条件:顺序线性表L已存在。*/
/* 操作结果:将L重置为空表     */
Status ClearList(SqList *L)
 { 
   (*L).length = 0;
   return OK;
 }

顺序线性表获得元素操作的代码:

/* 初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/* 操作结果:用e返回L中第i个数据元素的值*/
Status GetElem (SqList L,int i,ElemType *e)
{
    if (L.length==0 || i<1 || i>L.length)
        return ERROR;
    *e = L.data[i-1];
    return OK;
}

顺序线性表查找元素操作的代码:

/* 初始条件:顺序线性表L已存在。*/
/* 操作结果:若找到与e相等的值,则返回序号,否则返回0代表失败*/
Status LocateElem (SqList L,ElemType e)
{
    ElemType k;
    for (k=0;k<L.length;k++)
    {
        if (L.data[k] == e)
        {
            break;
            return k+1;
        }
    }
    return 0;
}

顺序线性表插入元素操作的代码:

/* 初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1*/
Status ListInsert (SqList *L,int i,ElemType e)
{
    int k;
    if (L->length==MAXSIZE)   /*线性表已满*/
        return ERROR;
    if (i<1 || i>L->length+1) /*i不在范围内*/
        return ERROR;
    if (i<=L->length)         /*插入数据不在表尾*/
    {
        for (k=L->length-1;k>=i-1;k--)
            L->data[k+1] = L->data[k];
    }
    L->data[i-1] = e;         /*将新元素插入*/
    L->length++;
    return OK;
}

顺序线性表删除元素操作的代码:

/* 初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1*/
Status ListDelete(SqList *L,int i,ElemType *e)
{
    int k;
    if (L->length==0)        /*线性表为空*/
        return ERROR;
    if (i<1 || i>L->length)  /*删除位置不正确*/
        return ERROR;
    *e = L->data[i-1];       
    if (i<L->length)         /*如果删除不是最后位置*/
    {
        for (k=i;k<L->length;k++) /*将删除位置后继元素前移*/
            L->data[k-1] = L->data[k];
    }
    L->length--;
    return OK;
}

4.线性表顺序存储结构的优缺点

  • 优点
    • 无需为表示表中元素之间的逻辑关系而增加额外的存储空间
    • 可以快速地存取表中任意位置的元素
  • 缺点
    • 插入和删除操作需要移动大量元素
    • 当线性表长度变化较大时,难以确定存储空间的容量
    • 造成存储空间的“碎片”

二、线性表的链式存储结构

单链表

单链表
单链表2

线性表的单链表结构:

/* 线性表的单链表存储结构 */
typedef struct Node
{
    ElemType data;
    struct Node *next;
}Node;
typedef struct Node *LinkList; /* 定义LinkList */

单链表的读取操作代码:

/* 初始条件:单链表L已存在,1<=i<=ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem (LinkList L,int i,ElemType *e) 
{
    int j;
    LinkList p;         /* 声明一指针p */
    p = L->next;        /* 让指针p指向链表L的第一个节点 */
    j = 1;              /* j为计数器 */
    while (p && j<i)
    {
        p = p->next;
        ++j;
    }
    if (!p || j>i)
        return ERROR;
    *e = p->data;
    return OK;
}

单链表的插入操作代码:

单链表插入

/* 初始条件:单链表L已存在,1<=i<=ListLength(L) */
/* 操作结果:在L中第i个节点位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert (LinkList *L,int i,ElemType e)
{
    int j;
    LinkList p,s;
    j = 1;
    while (p && j<i)
    {
        p = p->next;
        ++j;
    }
    if (!p || j>i)
        return ERROR;
    s = (LinkList)malloc(sizeof(Node));
    s->data = e;                /* 把新的数据元素存入s的数据域 */
    s->next = p->next;    /* 把p的后继节点赋值给s的后继 */
    p->next = s;                /* 把s赋值给p的后继 */
    return OK;
}

单链表的删除操作代码:
单链表删除

/* 初始条件:单链表L已存在,1<=i<=ListLength(L) */
/* 操作结果:删除L的第i个节点,并用e返回其值,L的长度减1 */
Status ListDelete (LinkList *L,int i,ElemType *e)
{
    int j;
    LinkList p,q;
    p = *L;
    j = 1;
    while (p && j<i)
    {
        p = p->next;
        ++j;
    }
    if (!p || j>i)
        return ERROR;
    q = p->next;                /* 将q指向p的后继 */
    p->next = q->next;      /* 将q的后继赋值给p的后继 */
    *e = q->data;           /* 将q中的数据给e */
    free(q);                    /* 回收节点q,释放内存 */
    return OK;
}

单链表的整表创建:

  • 头插法:
    头插法
void CreateListHead (LinkList *L,int n)
{
    LinkList *p;
    int i;
    srand(time(0));
    *L = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;
    for (i=0;i<n;i++)
    {
        p = (LinkList)malloc(sizeof(Node));
        p->data = rand()%100+1;
        p->next = (*L)->next;
        (*L)->next = p;
    }
}
  • 尾插法:
    尾插法
void CreateListTail (LinkList *L,int n)
{
    LinkList p,r;
    int i;
    srand(time(0));
    *L = (LinkList)malloc(sizeof(Node));
    r = *L;
    for (i=0;i<n;i++)
    {
        p = (Node*)malloc(sizeof(Node));
        p->data = rand()%100+1;
        r->next = p;
        r = p;
    }
    r->next = NULL;
}

单链表的整表删除

Status ClearList (LinkList *L)
{
    LinkList p,q;
    p = (*L)->next;
    while (p)
    {
        q = p->next;
        free(q);
        p = q;
    }
    (*L)->next = NULL;
    return OK;
}

单链表结构与顺序存储结构优缺点

  • 存储分配方式

    • 顺序存储结构用一段连续的存储单元依次存储线性表的数据元素

    • 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素

  • 时间性能

    • 查找

      • 顺序存储结构 O(1)

      • 单链表 O(n)

    • 插入和删除

      • 顺序存储结构需要平均移动表长一半的元素,时间为 O(n)

      • 单链表在线出某位置的指针后,插入和删除时间仅为 O(1)

  • 空间性能

    • 顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢

    • 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制


静态链表

“用数组描述的链表叫做静态链表”,结构体数组分别存放数据(data域)和游标(Cursor,为0时无指向)。
静态链表

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 1000    /* 存储空间起始分配量 1000 */
#define OK 1
#define ERROR 0

typedef int ElemType;       /* 视具体情况而定 假定数组存int */
typedef int Status;

/* 线性表的静态链表存储结构 */
typedef struct
{
    ElemType data;
    int cur;
}Component,StaticLinkList[MAXSIZE];

/* 获得表长 */
int ListLength (StaticLinkList L)
{
    int j=0;
    int i=L[MAXSIZE-1].cur;
    while (i)
    {
        i = L[j].cur;
        j++;
    }
    return j;
}

/* 初始化 */
/* 将一维数组space中各分量链成一个备用链表,space[0].cur为头指针,"0"表示空指针 */
Status InitList (StaticLinkList space)
{
    int i;
    for (i=0;i<MAXSIZE-1;i++)
        space[i].cur = i+1;
    space[MAXSIZE-1].cur = 0;           /* 目前静态链表为空,最后一个元素的cur为0 */
    return OK;
}

/* 预分配空闲空间 */
/* 若备用空间链表非空,则返回分配的结点下标,否则返回0 */
int Malloc_SLL (StaticLinkList space)
{
    int i = space[0].cur;                   /*返回的第一个备用空闲的下标 */

    if (space[0].cur)
        space[0].cur = space[i].cur;        /*把要用的元素的下一个分量用来做备用 */  

    return i;
}

/*  将下标为k的空闲结点回收到备用链表 */
void Free_SSL (StaticLinkList space,int k)
{
    space[k].cur = space[0].cur;        /* 把第一个元素的cur值赋给要删除的分量cur */
    space[0].cur = k;                   /* 把要删除的分量下标赋值给第一个元素的cur */
}

/*  在L中第i个元素之前插入新的数据元素e   */
Status ListInsert (StaticLinkList L,int i,ElemType e)
{
    int j,k,l;
    k = MAXSIZE-1;
    if (i<1 || i>ListLength(L)+1)
        return ERROR;
    j = Malloc_SLL(L);        /* 获得空闲分量的下标 */
    if (j)
    {
        L[j].data = e;
        for (l=1;l<=i-1;l++)    /* 找到第i个元素之前的位置 */
            k = L[k].cur;
        L[j].cur = L[k].cur;    /* 把第i个元素之前的cur赋值给新元素的cur */
        L[k].cur = j;           /* 把新元素的下标赋值给第i个元素之前元素的cur */
        return OK;
    }
    return ERROR;
}

/* 删除下标为i的元素 */
Status ListDelete (StaticLinkList L,int i)
{
    int j,k;
    if (i<1 || i> ListLength(L))
        return ERROR;
    k = MAXSIZE-1 ; 
    for (j=1;j<i-1;j++)
        k = L[k].cur;
    j = L[k].cur;
    L[k].cur = L[j].cur;
    Free_SSL (L,j);
    return OK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值