• 售前

  • 售后

热门帖子
入门百科

Leap Day4——数据结构与算法 链表表示和实现

[复制链接]
吴秀锦 显示全部楼层 发表于 2022-1-13 02:23:07 |阅读模式 打印 上一主题 下一主题
目录

1、链表的概念
1.1 链表的定义
1.2 头指针、头结点和首元结点
1.3 空表的表示
1.4 头结点的好处
1.5 头结点的数据域
1.6 链表(链式存储结构)的特点
2、单链表的定义
3、单链表的基本操作
3.1 初始化
3.2 判断空表
3.3 销毁
3.4 清空
3.5 求单链表的表长
3.6 取第i个元素值
3.7 查找
3.7.1 按值查找
3.7.2 按位查找
3.8 插入
3.9 删除
4、建立单链表
4.1 头插法——每次插在头结点的后头
4.2 尾插法——元素插入在链表的尾部

1、链表的概念

1.1 链表的定义

线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针
1.2 头指针、头结点和首元结点



头指针:是指向链表中第一结点的指针;
首元结点:是指链表中存储第一个数据元素a1的结点;
头节点:是在链表的首元结点之前附设的一个结点;
1.3 空表的表示

1)无头结点的链表:头指针为空时表示空表
2)有头结点的链表:当头结点的指针域为空时表示空表
1.4 头结点的好处



  • 由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表上的其他位置上的操作一致,无须进行特殊处理。
  • 无论链表是否为空,其头指针都指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也就得到了统一。
1.5 头结点的数据域

头结点的数据域可以为空,也可以存放线性表长度等附加信息,但此结点不能计入链表长度值
1.6 链表(链式存储结构)的特点

1)结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上还不相邻
2)访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其他结点,所以寻找的第一个结点和最后一个结点所花的时间不等(顺序存取法)
注意:顺序表是随机存取,顺序存储
链表是顺序存取,非顺序存储
2、单链表的定义

单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名,若头指针的名是:L,则把链表称为表L
不带头结点的单链表
定义链表头指针L:LinkList L;
定义结点指针P:LNode *p;
  1. <code>typedef struct LNode{       //定义单链表结点类型
  2.   ElemType data;           //每个结点存放一个数据元素
  3.   struct LNode *next;      //指针指向下一个结点
  4. }LNode,*LinkList;           //LinkList为指向结构体Lnode的指针类型
复制代码
3、单链表的基本操作

3.1 初始化

  1. <code>//初始化一个空的单链表
  2. bool InitList(LinkList &L){
  3.     L=new LNode;//或L=(LinkList)malloc(sizeof(LNode));
  4.     L->next=NULL;       //空表,暂时还没有任何结点。防止脏数据
  5.     return OK;
  6. }
复制代码
3.2 判断空表

  1. <code>int LIstEmpty(LinkList L){//若L为空表,贼返回1,否则返回0
  2.     if(L—>next)//非空
  3.         return 0;
  4.     else
  5.         return 1;
  6. }
复制代码
3.3 销毁


 

L指向头结点的指针域,这样就指向了下一个结点,然后再指向下一个结点的指针域,不断操作,销毁单链表
  1. <code>Status DestroyList_L(LinkLIst &L){
  2.     Lnode *p;//LinkList p;
  3.     while(L){
  4.         p=L;//将头结点的指针赋值给p,从头结点开始
  5.         L=L->next;
  6.         delete p;
  7.     }
  8. }
复制代码
3.4 清空

链表仍存在,但链表中无元素,成为空链表(头指针和头结点仍然在)
算法思路:依次释放所有结点,并将头结点指针域设置为空

 

  1. <code>Status ClearList(LinkList & L){
  2.     Lnode *p,*q;//或者LinkList p,q;
  3.     p=L->next;
  4.     while(p){   //没到表尾
  5.         q=p->next;
  6.         delete p;
  7.         p=q;
  8.     }
  9.     L->next=NULL;   //头结点指针为空
  10.     return OK;
  11. }
复制代码
3.5 求单链表的表长

  1. <code>int ListLength_L(LinkList L){
  2.     LinkList p;
  3.     p=L->next;
  4.     i=0;
  5.     while(p){
  6.         i++;
  7.         p=p->next;
  8.     }
  9.     return i;
  10. }
复制代码
3.6 取第i个元素值

  1. <code>Status GetElem_L(LinkList L,int i,ElemType &e){
  2.     p=L->next;  //初始化
  3.     j=1;        //初始化
  4.     while(p&&j<i){  //向后扫描,直到p指向第i个元素或p为空
  5.         p=p->next;
  6.         j++;
  7.     }
  8.     if(!p\\j>i) return ERROR;   //第i个元素不存在
  9.     e=p->data;                  //取第i个元素
  10.     return OK;
  11. }//GetElem_L
复制代码
3.7 查找

3.7.1 按值查找

  1. <code>//按值查找,找到数据域==e的结点(带头结点)
  2. LNode LocateElem(LinkList L,ElemType e){
  3.    LNode p=L->next;
  4.    //从第1个结点开始查找数据为e的结点
  5.    while(p&&p->data!=e)
  6.        p=p->next;
  7.    return p;   //找到后返回该结点的指针,否则返回NULL
  8. }
复制代码
3.7.2 按位查找

  1. <code>//按位查找,返回第i个元素(带头结点)
  2. LNode GetElem(LinkList L,int i){
  3.    if(i<0)
  4.        return NULL;
  5.    LNode *p;               //指针p指向当前扫描到的结点
  6.    int j=0;                //当前p指向的是第几个结点
  7.    p=L;                    //L指向头结点,头结点是第0个结点(不存数据)
  8.    while(p!=NULL&&j<i){    //循环找到第i个结点
  9.        p=p->next;
  10.        j++;
  11.    }
  12.    return p;
  13. }
复制代码
3.9 删除

算法步骤:
第一步、首先找到ai-1的存储位置p,保存要删除的ai的值
第二步、令p->next指向ai-1;
 


将i的指针域(i+1的指针)指向i-1的指针域(i的指针):p->next = p->next ->next
  1. <code>Status ListInsert_L(LinkLIst &L,int i,ElemType e){
  2.     p=L;
  3.     j=0;
  4.     while(p&&j<i-1){//寻找第i-1结点,p指向i-1结点
  5.         p=p->next;
  6.         j++;
  7.     }
  8.     if(!p||j>i-1)//大于表长+1或者小于1,插入位置非法
  9.         return ERROR;
  10.    s=new LNode;//生成新结点s,将结点s的数据域置为e
  11.    s->data = e;
  12.    s->next = p->next;
  13.    p->next = s;
  14.    return OK;
  15. }//ListInsert_L
复制代码
4、建立单链表

4.1 头插法——每次插在头结点的后头

1)从一个空表开始,重复读入数据
2)生成新结点,将读入数据存放到新结点的数据域中
3)从最后一个结点开始,依次将各结点插入到链表的前端

 



  1. <code>Status ListDelete_L(LinkList &L,int i,ElemType &e){
  2.    p=L;
  3.    j=0;
  4.    while(p->next&&j<i-1){//寻找第i个结点,并令p指向其前驱
  5.        p=p->next;
  6.        j++;
  7.    }
  8.    if(!(p->next)||j>i-1)//删除位置不合适
  9.        return ERROR;
  10.    q=p->next;//临时保存被删结点的地址以备释放
  11.    p->next=q->next//改变删除结点前驱结点的指针域
  12.    e=q->data;//保存删除结点的数据域
  13.    delete q;//释放删除结点的空间
  14.    return OK;
  15. }//ListDelete_L
复制代码
4.2 尾插法——元素插入在链表的尾部


 

  1. <code>void CreateList_H(LinkList &L,int n){
  2.    //逆位序输入n个元素的值,建立带表头结点的单链表L
  3.    L=(LinkList)malloc(sizeof(LNode));//L = new LNode
  4.    L->next=NULL;           //先建立一个带头结点的空链表
  5.    LNode *p;
  6.    for(int i=n;i>0;i--){
  7.        p=(LinkList)malloc(sizeof(LNode));//生成新结点*p
  8.        cin>>p->data;       //输入元素值复制给新结点*p的数据域
  9.        p->next=L->next;L->next=p;  //将新结点*p插入到头结点之后   
  10.    }
  11. }
复制代码
来源:https://blog.caogenba.net/m0_61163395/article/details/122421959
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作