线性表的链式表示及实现

简介: 线性表的链式表示及实现

@TOC

链式存储相关概念

  • 用一组物理地址任意的存储单元来存放线性表的数据元素;
  • 这组存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置;
  • 链表中元素的逻辑次序和物理次序不一定相同。

结点:数据元素的存储映像。由数据域和指针两部分组成。
链表:n个结点由指针链组成一个链表。
它是线性表的链式存储映像,称为线性表的链式存储结构。

单链表、双链表、循环链表

  • 结点只有一个指针域的链表,称为单链表或线性链表
  • 结点有两个指针域的链表,称为双链表
  • 收尾相连的链表称为循环链表

头指针、头结点和首元结点

  • 头指针:是指向链表中第一个结点的指针
  • 首元结点:是指链表中存储第一个数据元素a~1~的结点
  • 头结点:是在链表的首元结点之前附设的一个结点

链表(链式存储结构)的特点

  • 结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻;
  • 访问是只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点,所以寻找第一个结点和最后一个结点所花的时间不等。

单链表

单链表的存储结构

在这里插入图片描述

typedef struct Lnode {  //声明结点的类型和指向结点的指针类型
    ElemType data ;     //结点的数据域
    struct Lnode *next;  //指针域
}LNode,*LinkList;     //LinkList为指向结构体Lnode的指针类型

例如,存储学号、姓名、成绩的单链表结点类型定义如下:

typedef Struct {
    char num[8];  //数据域
    char name[8];  //数据域
    int score;    //数据域
}ElemType;

typedef struct Lnode {
    ElemType data ;     //结点的数据域
    struct LNode *next;  //指针域
}    

单链表的操作

单链表的初始化

即构造一个空表

Status InitList_L(LinkList &L) {
    L = new LNode;   //或L = (LinkList)malloc (sizeof(LNode))
    L->next = NULL;
    return OK;
}
销毁单链表L
Status DeleteList_L(LinkList &L){
    LNode *p;
    while(L){
        p=L;
        L=L->next;
        delete p;
    }
}
清空链表L
Status ClearList_L(LinkList &L){   //将L重置为空表
    LNode *p,*q;
    p = L->next;
    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;
    i=0;
    while(p){
        i++;
        p = p->next;
    }
    return i;
}
查找第i个元素
Status GetElem_L(LinkList L,int i,ElenType &e){
    //获取线性表L中第i个元素的内容,通过变量e返回
    p = L->next;
    j = 1;
    while(p&&j<i){
        p = p->next;
        j++;
    }
    if(!p||j>i){
        return ERROR;
    }
    e = p->data;
    return OK;
}
安值查找
int LocateElem_L(LinkList L,ElenType e){
//在线性表L中查找值为e的数据元素的位置序号
    p = L->next;
    j=1;
    while(p&&p->data!=e){
        p = p->next;
        j++;
    }
    if(p) return j;
    else return 0;
}
单链表的插入
Status ListInsert_L(LinkList &L,int i,ElemType e){
//在L中第i个元素前插入数据元素e
    p = L;
    j = 0;
    while(p&&j<i-1){
        p = p->next;
        j++;
    }
    if(p||j>i-1) return ERROR;
    s = new LNode;
    s->data = e;
    s->next = p->next;
    p->next = s;
}
单链表的删除
Status ListDelete_L(LinkList &L,int i,ElemType &e){
//将L中第i个数据元素删除
    p = L;
    j = 0;
    while(p&&j<i-1){
        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;
}
头插法建立链表
void CreateList_H(LinkList &l,int n){
    L = new LNode;
    L->next = NULL;
    for(i = n;i>0;i--){
        p = new LNode;
        cin>>p->data;
        p->next = L->next;
        L->next = p;
    }
}
尾插法建立链表
void CreateList_R(LinkList &l,int n){
    L = new LNode;
    L->next = NULL;
    r = L;
    for(i = 0;i<n;i++){
        p = new LNode;
        cin>>p->data;
        p->next = NULL;
        r->next = p;
        r = p;
    }
}

循环链表

一种头尾相连的链表(即:表中最后一个结点的指针域指向头结点,整个链表形成一个环)。
从表中任一结点出发均可找到表中其他结点。

双向链表

在单链表的每个结点里在增加一个指向其直接前驱的指针域prior,这样链表中就形成了有两个方向不同的链。

双向链表的存储结构

typede struct DuLNode {
    ElemType data;
    struct DuLNode *prior,*next;
}DuLNode,*DulLinkList;

双向链表的操作

双向链表的插入
void ListInsert_DuL(DuLinkList &L,int i,ElemType e){
    //在带头结点的双向链表L中第i个位置之前插入元素e
    if(!(p = GetElemP_DuL(L,i))) return ERROR;   //得到第i个位置的结点p
    s = new DuLNode;
    s->data = e;
    s->prior = p->prior;
    p->prior->next = s;
    s->next = p;
    p->prior = s;
    return OK;
}
双向链表的删除
void ListDelete_DuL(DuLinkList &L,int i,ElemType &e){
    //删除带头结点的双向链表L的第i个元素,并用e返回
    if(!(p = GetElemP_DuL(L,i))) return ERROR;   //得到第i个位置的结点p
    e = p->data;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
    return OK;
}

链式存储总结

优点

  • 结点空间可以动态申请和释放;
  • 数据元素的逻辑次序靠结点的指针指示,插入和删除时不需要移动元素。

缺点
-存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大;
链式存储结构是非随机存取结构。对任一结点的操作都要从头指针链查到该结点,这增加了算法的复杂度。

顺序表和链表的比较

在这里插入图片描述

目录
相关文章
|
测试技术 开发工具 git
Commit Message 规范
Commit Message 规范
234 0
|
算法 安全 Go
Go语言哈希函数不可不知的N个实战技巧
Go语言哈希函数不可不知的N个实战技巧
550 0
|
9月前
|
API 网络架构
WordPress定时发布插件
这是一款用于WordPress的定时发布插件,可将后台、REST API及草稿箱中的文章按设定时间自动发布,避免文章立即上线。支持指定或随机延迟发布,以及周期性发布草稿箱内容。插件依赖WordPress计划任务功能,确保稳定运行。附产品截图展示设置界面。
215 10
|
11月前
|
人工智能 自然语言处理 算法
随机的暴力美学蒙特卡洛方法 | python小知识
蒙特卡洛方法是一种基于随机采样的计算算法,广泛应用于物理学、金融、工程等领域。它通过重复随机采样来解决复杂问题,尤其适用于难以用解析方法求解的情况。该方法起源于二战期间的曼哈顿计划,由斯坦尼斯拉夫·乌拉姆等人提出。核心思想是通过大量随机样本来近似真实结果,如估算π值的经典示例。蒙特卡洛树搜索(MCTS)是其高级应用,常用于游戏AI和决策优化。Python中可通过简单代码实现蒙特卡洛方法,展示其在文本生成等领域的潜力。随着计算能力提升,蒙特卡洛方法的应用范围不断扩大,成为处理不确定性和复杂系统的重要工具。
694 21
|
机器学习/深度学习 缓存 自然语言处理
一文揭秘|预训练一个72b模型需要多久?
本文讲述评估和量化训练大规模语言模型,尤其是Qwen2-72B模型,所需的时间、资源和计算能力。
1094 12
|
JSON 持续交付 数据中心
基础设施即代码(IaC)的实现途径
【8月更文挑战第18天】基础设施即代码(IaC)是现代云计算和DevOps实践中不可或缺的一部分。通过编写代码来定义和管理基础设施,可以实现自动化、可重复性、易于维护和高度可扩展的基础设施管理。通过选择合适的工具和方法,遵循最佳实践,企业可以显著提升基础设施的部署效率和管理水平。
|
机器学习/深度学习 计算机视觉
YOLOv10实战:SPPF原创自研 | SPPF_attention,重新设计加入注意力机制 | NEU-DET为案列进行展开
【7月更文挑战第1天】 优点:为了利用不同的池化核尺寸提取特征的方式可以获得更多的特征信息,提高网络的识别精度; 如何优化:在此基础上加入注意力机制,能够在不同尺度上更好的、更多的获取特征信息,从而获取全局视角信息并减轻不同尺度大小所带来的影响; SPPF_attention,重新设计加入注意力机制 ,在NEU-DEU任务中mAP50从0.683提升至0.703;
1391 3
|
SQL 数据可视化 数据库
Python中表格插件Tabulate的用法
Python中表格插件Tabulate的用法
1110 0
|
内存技术 芯片
MDK st-link下载STM32程序出现Internal command error和Error:Flash download failed. Target DLL
MDK st-link下载STM32程序出现Internal command error和Error:Flash download failed. Target DLL   是因为目标板的芯片处于休眠的状态,在尝试连接目标板时候也会出现报错Internal command ...
4029 0