数据结构与算法——线性表(老干妈笔记)


 线性表(list):由零个或多个数据元素组成的有限序列。

 

抽象数据类型的标准格式:

ADT      抽象数据类型名

Data      数据元素之间逻辑关系的定义

Operation     操作

endADT

 

线性表抽象数据类型定义:

ADT    线性表(List)

Data

线性表的数据对象集合为{a1,a2,...,an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且只有一个前驱元素,除最后一个元素an外,每个元素有且只有一个后继元素。数据元素之间的关系是一对一的关系。

Operation

InitList(*L):初始化操作,建立一个空表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

例: 实现两个线性表A、B的并集操作,使得集合 A = A U B。

void unionL(List *La, List Lb)
{
    int La_Len, Lb_Leng, i;
    
    ElemType e;
    La_Len = ListLenth(*La);
    Lb_Len = ListLenth(Lb);

    for(i=1; i<=Lb_Len; i++)
    {
        GetElem(Lb, i, &e);
        if(!LocateElem(*La,e))
        {
            
            ListInsert(La, ++La_Len, e);
        }
    }
}

 

线性表的存储结构:顺序存储结构、链式存储结构

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

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

#define MAXSIZE 20
typedef int ElemType;
typedef struct
{
    ElemType data[MAXSIZE];
    int length;    //线性表当前长度
}SqList;

顺序存储结构封装需要三属性:

1.存储空间起始位置,数组 Data,它的存储位置就是线性表存储空间的存储位置。

2.线性表的最大存储容量:数组的长度 MaxSize

3.线性表的当前长度 length

地址计算方法:

假设ElemType占用的是c个存储单元(字节),则

第i+1个元素与第i个元素的存储位置关系:Loc(ai+1) =  Loc(ai) + c;

第 i 个元素的存储位置可由 a1 推算得出:Loc(aI) = Loc(a1)+(i-1)* c

线性表的顺序存储结构,在存、读取数据时,不管在哪个位置,时间复杂度都是 O(1)。在插入或者删除时,时间复杂度都是 O(n)。

顺序线性表查找操作:

#define OK 1
#define Error 0
#define True 1
#define False 0

typedef int Status

//操作结果:用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;
}

顺序线性表插入操作:

​
Status ListInsert(Sqlist *L, int i, ElemType e)
{
    int k;
    
    if(L.Length = MaxSize)
    {
        return Error;
    }
    
    if(i<1 || i>L.Length+1)//当i不在范围时,+1是不能在L.Data[length+1]处插入,因为最多只有L.Data[Length-1],最多插在L.Data[Length]
    {
        return Error;
    }
    
    if(i<=L.Length)
    {
        for(k=L.Length-1; k>= i-1; k--)
    }
    
    L.Data[i]=e;
    L.Length++;
    
    return OK;
    
}

顺序线性表删除操作:

Status ElemDeLete(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;
}


线性表的链式存储结构:

链式存储结构中,除了要存储数据元素信息外【数据域】,还有存储他的后继元素的存储地址(指针)【指针域】。数据域和指针域两部分信息组成结点【Node】。

头指针:链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。【无论链表是否为空,头指针均不为空】

头结点:为操作统一方便而设立,放在第一个元素的结点之前,其数据域一般无意义(但也可用来存放链表的长度)。有了头结点,对在第一元素结点前插入结点和删除第一结点操作与其他结点的操作就统一了。

在C语言中可以用结构指针来描述单链表:

typedef struct Node
{
    ElemType data;//数据域
    struct Node* Next;//指针域
}Node;

typedef struct Node* LinkList;

单链表查找元素:

//单链表查找元素操作
/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e返回L中第i个元素的值 */

Status GetElem(LinkList L, int i, ElemType *e)
{
    int j;
    LinkList p;

    p=L->next;
    j=1;
        
    while(p && j<i)
    {
        p = p->next;
        ++j;
    }

    if(!p || j>i)
    {
        return Error;
    }
    
    *e = p->data;

    return OK;
}

单链表的插入操作:

//单链表插入操作

Status LinkInsert(Linklist *L, int i, ElemType e)
{
    int k=1;
    Linklist p,s;
    
    p = *L;

    while(p && k<i)    //寻找第i个结点
    {
        p = p->next;
        ++k;
    }

    if(!p || j>i)
    {
        return Error;
    }

    s = (LinsList)malloc(sizeof(Node));
    s->data = e;

    s-next = p-next;
    p->next = s;

    return OK;
}

单链表删除操作:

//单链表删除操作
//初始条件:顺序性链表L已存在,1<=i<=ListLength(L)
//操作结果:删除L的第i个元素,并用e返回其值,L的长度为-1

Status ListDelete(Linklist *L, int i, ElemType *e)
{
    int k=1;
    LinkList p,q;

    p= *L
    while(p->next && k<i)
    {
        p = p->next;
        ++k;
    }

    if( !(p->next) || j>i )
    {
        return Error;
    }

    q = p->next;
    p->next = q->next;

    *e = q->Data;
    free(q);

    return OK;
}

头插法建立单链表操作(生成链表结点次序和输入顺序相反):

//头插法建立单链表操作

void CreatLinkListHead(LinkList *L, int i, )
{
    int k=1;
    LinkList p;
    
    srand(time(0));//初始化随机数种子

    *L = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;

    for(k=1 ; k<i; k++)
    {
        p = (LinkList)malloc(sizeof(Node));//生成新节点
        p->data = rand()%100+1;
        p->next = (*L) -> next;
        (*L)->next = p;
    }
    
}

尾插法建立单链表操作:

//尾插法生成单链表

void CreatListTail(LinkList *L, int i)
{    
    int k;
    LinkList p,r;

    srand(time(0));
    *L = (LinkList)malloc(sizeof(Node));
    r = *L;

    for(k = 1; k < i; k++)
    {
        p = (LinkList)malloc(sizeof(Node));     
        p->data = rand()%100+1;
        r->next = p;
        r = p;                
    }    
    
    r->next = NULL;
}

猜你喜欢

转载自blog.csdn.net/LGM_1874/article/details/89647554