线性表

1.掌握线性表的定义、逻辑结构及其抽象数据类型等基本概念

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

ADT List{

数据对象:D={ai|ai∈ElemSet,i=1,2,...n,n>=0}//任意数据元素的集合

数据关系:R={<ai-1,ai>|ai-1,ai∈D,i=2,3,...n}//除第一个和最后一个外,每个元素都有唯一的前驱和后继

image-20240223142235356

基本操作:

​ InitList(&L):构造一个空的线性表L;

​ List&Length(L):初始条件:线性表L已经存在;操作结果:返回L中数据元素的个数;

​ GetElem(L,i,&e):初始条件:L存在,1<=i<=ListLenth(L);操作结果:用e返回L中第i个数据元素的位置

​ ...

}ADT List

2.重点掌握线性表的顺序存储

顺序存储:

1.把线性表的数据元素按逻辑顺序依次存放在一组地址连续的存储单元里。

2.顺序表是一种随机存储结构

3.结构类型

#define OVERFLOW 0//c++中0代表FLASE,其他TRUE,空也为FLASE
#define OK 1
#define ERROR 0
#define MAXSIZE 100
typedef struct{
    ElemType *elem;//空间存储的第一个位置,首址
    int length;//表长度
}SqList//顺序表的结构类型定义的名称

image-20240223152037029

Attention: 线性表的从1开始,而数组中元素下标从0开始

3.掌握顺序表的各种操作(插入、删除等)实现及其算法复杂度O(1)

1,顺序表初始化

Status InitList(SqList &L){//构造一个空的顺序表L
    L.elem=new ElemType[MAXSIZE];//为顺序表分配一个大小为MAXSIZE的数组空间
    if(!L.elem) exit(OVERFLOW);//如果分配成功为T不执行,分配为F则执行退出
    L.length=0;
    return OK
}

2.顺序表取值 O(1)

a.先判断指定的位置序号i值是否合理(1<=i<=L.length),不合理返回ERROR

b.若i值合理,则将第i个数据元素L.elem[i-1]赋给参数e,通过e返回第i个数据元素的传值。

Status GetElem(SqList L,int i,ElemType &e){
    if(i<1||i>L.length) return ERROR;
    e=L.elem[i-1];
    return OK;
}

3.顺序表按值查找

a.从第一个元素开始依次和e相比较,若找到相等元素L.elem[i],则查找成功,返回该元素的序号i+1(数组下标从0开始)

b.若查遍整个顺序表都没找到则返回0

c.平均时间复杂度为O(n)

int LocateElem(SqList L, ElemType e){
    for (i=0;i<L.length;i++){
		if(L.elem[i]==e) return i+1;
    }
    return 0;
}

3.顺序表插入元素O(n)

在第i个位置插入一个元素时,需要从最后一个元素即第n个元素开始,依次向后移动一个位置,知道第i个元素。

image-20240223154907942

a.判断插入位置是否合法

b.判断顺序表存储空间是否已满

c.将第n个元素至第i个元素依次向后移动一个位置,空出第i个位置(i=n+1时,无需移动)

d.将新元素e放入第i个位置

e.表长加1

Status Listinsert(Sqlist &L,int i,ElemType e){
    if((i<1)||(i>L.length+1)) return ERROR;
    if(L.length==MAXSIZE) return ERROR;
    for(int j=L.length-1;j>=i;j--){
        L.elem[j+1]=L.elem[j];
    }
    L.elem[i-1]=e;
    ++L.length;
    return OK;
}

4.顺序表删除元素O(n)

删除第i个元素时需要将第i+1个至第n个元素依次向前移动一个位置(i=n时无需移动)

image-20240223155732667

Status ListDelete(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;
    return OK;
}
4.线性表的链式表示和实现

单链表:

1.用一组任意的存储单元存储线性表中的数据元素。这组任意的存储单元可以是连续的,也可以是不连续的。链表中的逻辑顺序和物理顺序不一定相同。

2.为了确保元素之间的逻辑关系,在存储元素值的同时,还必须存储其后继节点的地址,指针(pointer)或链(link),这两部分组成了链表中的节点结构。

image-20240223143859505

data:数据域,存放元素的值

next:指针,存放当前节点的后继结点的地址

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

头结点:首元结点之前设置的一个结点,其指针指向首元结点

头指针:指向链表中第一个结点的指针。若链表设有头结点,则头指针所指结点为线性表的头结点;若链表不设头结点,则头指针所指结点为该线性表的首元结点。

image-20240223161847902

带头节点单链表为空:L->next=null 不带头结点为空时:L=null。

3.结构体

typedef struct LNode{//定义结点的类型名LNODE
    ElemType data;//存放元素值 ElemType可以是int,char等类型
    struct LNode *next; //指针域
}LNode,*LinkList;//LinkList是指向结构体LNode的指针类型

4.结点是通过动态分配内存和释放内存来实现的

p=(LNode *)malloc(sizeof(LNode));
//(LNode *)强制类型转换为结点型
//malloc函数分配了一个类型为LNode的结点变量的空间,并将其首地址放入指针变量p中
//c++中采用new创建新空间 new +ELemType
L=new LNode;
free(p);//动态释放指针p的内存区

(1)结点的赋值

LNode *p;
p=(LNode*)malloc(sizeof(LNode));
p->data=20;
p->next=null;

image-20240223144932834

(2)单链表的初始化

1.生成新结点作为头结点,用头指针L指向头结点

2.头结点的指针域为空

Status InitList(LinkList &L){
    L=new LNode;//生成新结点,同时用头指针L指向头结点
    L->next=null;
    return ok;
}

(3)单链表的取值O(n)

1.用指针p指向首元结点,用j做计数器初值赋1

2.从首元结点开始向下访问,只要指针p不为空,并且没有达到序号为i。p指向下一个,j++

3.退出循环时,如果指针p为空,或j>i说明序号i不合法;否则取值成功,此时j=i,p指的结点就是要找的第i个结点,用参数e保存结点的数据域

Status GetElem(LinkList L,int i, ELemType &e){
    p=L->next;
    j=1;
    while(p&&j<i){
		p=p->next;
        ++j;
    }
    if(!p||j>i) return ERROR;//说明i不合法,i>J或i<0
    e=p->data;
    return OK;
}

(4)单链表的按值查找 O(n)

1.p指向首元结点

2.同上

3.返回p。若查找成果则p为结点地址值,若失败,p为空

LNode *LocateELem(LinkList L, Elemtype e){
    p=L->next;
    while(p&&P->data !=e){
        p=p->next;
    }
    return p;
}

(5)单链表的插入O(n)

image-20240223165150965

将值为e的新结点插入到第i个结点的位置上,即插入到结点ai-1与ai之间。

1.查找结点ai-1并由指针p指向该结点

2.生成一个新结点*s

3.*s的数据域为e

4.将*s的指针域指向结点ai

5.将p的指针域指向s

Status Listinser(LinkList &L,int i,Elemtype e){
    p=L->next;
    j=1;
    while(p&&(J<i)){
        p=p->next;
        ++j;
    }
    if(!p||j>i) return ERROR;
    s=new LNode;
    s->date =e;
    s->next=p->next;
    p->next=s;
    return ok;
}

(6)单链表的删除O(n)

删除第i个结点

1.查找结点ai-1并使p指向

2.生成新结点*q,临时保存待删除结点ai的地址

3.将结点*p的指针指向ai后继结点

4.释放结点ai的空间

Status ListDelte(LinkList &L, int i){
    p=L->next;
    int j=1;
    while(!p||j<i){
        p=p->next;
        ++j;
    }
    if(!(p->next)||(j>i)) return ERROR;
    q=new LNode;
    q=p->next;
    p->next=q->next;
    delete q;
    return OK;
}