数据结构(考研)第二章 线性表

第二章 线性表

2.1 线性表的定义和基本操作

2.1.1 线性表的定义

线性表是具有相同数据类型的n个数据元素的有限序列。其中n为表长。

其中,线性表的第一个元素称为表头元素,最后一个元素称为表尾元素,除了第一个元素外,线性表中每一个元素都有直接后继,除了最后一个元素外,线性表中每一个元素都有直接前驱。

image-20220506155201493

2.1.2 线性表的基本操作

InitList(&L):初始化表。构造一个空的线性表。

DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间。

LocateElem(L,e):按值查找操作。在表中L查找具有给定关键字值的元素。

GetELem(L):按位查找操作。获取表L中第i个位置的元素的值。

Listlnsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e.

LlstDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。

PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值。
Empty(L):判空操作。若l为空表,则返回TRUE,否则返回FALSE。

Length(L):求表长。返回线性表L的长度,即L中数据元素的个数。

2.2 线性表的顺序表示

顺序表的实现–静态分配

#define MaxSize 10
typedef struct{
    ElemType data[MaxSize];//数据元素类型
    int length;
}SqList;
//基本操作——初始化一个顺序表
void InitList(SqList &L){
    for(int i = 0;i < MaxSize;i++)
        L.data[i] = 0;
    L.length = 0;
}
int main(){
    SqList L;//先声明一个顺序表
    InitList(L);
}

顺序表的实现–动态分配

#define InitSize 10//顺序表的初始长度
#define <stdlib.h>
typedef struct{
    ElemType *data;//指示动态分配数组的指针
    int MaxSize;
    int length;
}SeqList;
void InitList(SeqList &L){//初始化
    L.data = (int *)malloc(InitSize*sizeof(int));
    L.length = 0;
    L.MaxSize = InitSize;
}
void IncreaseSize(SeqList &L, int len){//动态扩容
    int *p = L.data;
    L.data = (int *)malloc((L.MaxSize + len)*sizeof(int));
    for(int i = 0;i<L.length;i++){
        L.data[i] = p[i];//将数据复制到新区域
    }
    L.MaxSize = L.MaxSize+len;
    free(p);
}

顺序表的实现–插入操作

bool listInsert(SeqList &L, int i, ElemType e) {
    if (i < 1 || i > L.maxSize + 1) {
        return false;
    }
    if (L.length >= MaxSize) {
        return false;
    }
    //将第i个元素及之后的元素右移
    for (int j = L.length; j >= i; j--) {
        L.data[j] = L.data[j - 1];
    }
    L.data[i - 1] = e;
    L.length++;
    return true;
}

顺序表的实现–删除操作

bool listDelete(SeqList &L,int i,ElemType &e){
    if (i<1 || i>=L.length + 1) return false;
    if(L.length >= L.maxSize) return false;
    e = L.data[i-1];
    for (int j = i; j < L.length; ++j) {
        L.data[j-1] = L.data[j];
    }
    L.length--;
    return true;
}

顺序表的实现–尾插法

void listInsert(SeqList &L, ElemType e) {
    L.data[L.length] = e;
    L.length++;
}

顺序表的实现–按值查找操作

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

main函数

int main() {
    initList(L);
    listInsert(L, 0);
    listInsert(L, 1);
    listInsert(L, 2);
    listInsert(L, 3);
    listInsert(L, 4);
//    int p;
//    bool flag = listDelete(L,2,p);
//    std::cout<< flag << std::endl;
    printf("%d",LocateElem(L,3));
    for (int i = 0; i < L.length; ++i) {
        printf("%d\n", L.data[i]);
    }
    return 0;
}

特点:

  • 随机访问
  • 存储密度高
  • 拓展容量不方便
  • 插入删除元素不方便

2.3 线性表的链式表示

2.3.1 单链表的定义

线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。

2.3.1 单链表的实现

定义头文件

#ifndef DATASTRUCTURE_SINGLELINKEDLIST_H
#define DATASTRUCTURE_SINGLELINKEDLIST_H
#define ElemType int
typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode, *LinkedList;
#endif //DATASTRUCTURE_SINGLELINKEDLIST_H

单链表的实现–初始化

bool InitList(LinkedList &L){
    L = (LNode *)malloc(sizeof(LNode));
    if (L== nullptr)return false;
    L->next = nullptr;
    return true;
}

单链表的实现–头插法

LinkedList List_HeadInsert(LinkedList &L){
    LNode *s;int x;
    L = (LinkedList)malloc(sizeof(LNode));//创建头结点
    L->next = nullptr;
    scanf("%d",&x);
    while (x!=9999){
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        scanf("%d",&x);
    }
    return L;
}

单链表的实现–尾插法

LinkedList List_TailInsert(LinkedList &L){
    int x;
    LNode *s, *r = L;
    L = (LinkedList)malloc(sizeof(LNode));//创建头结点
    s = (LNode *)malloc(sizeof(LNode));
    scanf("%d",&x);
    while (x!=9999){
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        r = s;
        scanf("%d",&x);
    }
    r->next = nullptr;
    return L;
}

Note:使用LinkList强调这是一个单链表,使用LNode * 强调这是一个结点

单链表的实现–按位序插入

bool ListInsert(LinkedList &L,int i,ElemType e){
    if (i<1) return false;
    LNode *p;
    int j = 0;//当前p指向的是第几个结点
    p = L;
    while (p!= nullptr && j < i-1){
        p = p->next;
        j++;
    }
    if (p== nullptr)return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

单链表的实现–指定结点的前插操作

bool InsertPriorNode(LNode *p,LNode *s){
    if (p == nullptr || s == nullptr)return false;
    s->next = p->next;
    p->next = s;
    ElemType temp = p->data;
    p->data = s->data;
    s->data = temp;
    return true;
}

单链表的实现–指定结点的后插操作

bool InsertNextNode(LNode *p,ElemType e){
    if (p== nullptr)return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

单链表的实现–按位序删除

bool ListDelete(LinkedList &L,int i,ElemType &e){
    if (i<1) return false;
    LNode *p;
    int j = 0;
    p = L;
    while (p!= nullptr && j < i-1){
        p = p->next;
        j++;
    }
    if (p== nullptr || p->next == nullptr)return false;
    LNode *q = p->next;
    e = q->data;
    p->next = q->next;
    free(q);
    return true;
}

单链表的实现–指定结点删除

bool DeleteNode(LNode *p){
    if (p== nullptr)return false;
    LNode *q = p->next;
    p->data = p->next->data;
    p->next = q->next;
    free(q);
    return true;
}

单链表的实现–按位查找

LNode * GetElem(LinkedList L,int i){
    int j = 1;
    LNode *p = L->next;
    if (i == 0)return  L;
    if (i < 1) return nullptr;
    while (p!= nullptr && j<i){
        p = p->next;
        j++;
    }
    return p;
}

单链表的实现–按值查找

LNode * LocateElem(LinkedList L,ElemType e){
    LNode *p = L->next;
    while (p!= nullptr && p->data != e){
        p = p->next;
    }
    return p;
}

带头结点和不带头结点的比较:
不带头结点:写代码麻烦!对第一个数据节点和后续数据节点的处理需要用不同的代码逻辑,对空表和非空表的处理也需要用不同的代码逻辑; 头指针指向的结点用于存放实际数据;
带头结点:头指针指向的头结点不存放实际数据,头结点指向的下一个结点才存放实际数据;

2.3.2 双链表的实现

双链表的实现–初始化双链表

bool InitDLinkList(DLinklist &L){
    L = (DNode *)malloc(sizeof(DNode));
    if (L== nullptr)return false;
    L->prior = nullptr;
    L->next = nullptr;
    return true;
}

双链表的实现–在p结点之后插入s结点

bool InsertNextDNode(DNode *p,DNode *s){
    s->next = p->next;
    if (p->next != nullptr)p->next->prior = s;
    s->prior = p;
    p->next = s;
}

双链表的实现–双链表的删除

bool DeleteNextDNode(DNode *p){
    if (p == nullptr) return false;
    DNode *q = p->next;
    if (q == nullptr) return false;
    p->next = q->next;
    if (q->next != nullptr)
        q->next->prior = p;
    free(q);
    return true;
}

循环链表–循环单链表

最后一个结点的指针不是NULL,而是指向头结点

typedef struct LNode{            
    ElemType data;               
    struct LNode *next;  
}DNode, *Linklist;

/初始化一个循环单链表
bool InitList(LinkList &L){
    L = (LNode *)malloc(sizeof(LNode)); //分配一个头结点
    if(L==NULL)             //内存不足,分配失败
        return false;
    L->next = L;            //头结点next指针指向头结点
    return true;
}

//判断循环单链表是否为空(终止条件为p或p->next是否等于头指针)
bool Empty(LinkList L){
    if(L->next == L)
        return true;    //为空
    else
        return false;
}

//判断结点p是否为循环单链表的表尾结点
bool isTail(LinkList L, LNode *p){
    if(p->next == L)
        return true;
    else
        return false;
}

循环链表–循环双链表

表头结点的prior指向表尾结点,表尾结点的next指向头结点

typedef struct DNode{          
    ElemType data;               
    struct DNode *prior, *next;  
}DNode, *DLinklist;

//初始化空的循环双链表
bool InitDLinkList(DLinklist &L){
    L = (DNode *) malloc(sizeof(DNode));    //分配一个头结点
    if(L==NULL)            //内存不足,分配失败
        return false;  
    L->prior = L;          //头结点的prior指向头结点
    L->next = L;           //头结点的next指向头结点
}

void testDLinkList(){
    //初始化循环单链表
    DLinklist L;
    InitDLinkList(L);
    //...
}

//判断循环双链表是否为空
bool Empty(DLinklist L){
    if(L->next == L)
        return true;
    else
        return false;
}

//判断结点p是否为循环双链表的表尾结点
bool isTail(DLinklist L, DNode *p){
    if(p->next == L)
        return true;
    else
        return false;
}

静态链表

#define MaxSize 50
#define ElemType int
typedef struct {
    ElemType data;
    int next;
}SlinkList[MaxSize];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bestkasscn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值