首页 > 其他分享 >单链表的实现和操作

单链表的实现和操作

时间:2024-07-26 18:27:32浏览次数:11  
标签:结点 单链 Lnode 实现 next 链表 操作 指针

目录

一.前言

二.单链表的定义和结构

三. 单链表的操作


一.前言

        线性表的链式表示又称为非顺序映像或链式映像。简而言之,链表可以理解为由指针链连接的n个结点组成的。其中每一个结点包括数据域和指针域。值得注意的是,与顺序表不同,链表中的逻辑次序与物理次序不一定相同。

二.单链表的定义和结构

        我们称结点只有一个指针域的链表称为单链表或线性链表。注意区分我们后面要学习的双向链表和循环链表。下面我们来看下单链表的组成,单链表可以是这样的结构:

它包含一个头指针,头结点以及所有的结点,其中存储的第一个数据元素的结点称为首元结点。

其中,头指针是必要的,头结点可有可没有。当我们的单链表没有头结点的时候,头指针为空时表示这个单链表是空表。有头结点的时候,头结点的指针域为空时表示空表。 

 由于单链表是由表头唯一确定的,所以单链表可以用头指针的名字来命名,若头指针是L,则把链表称为表L。下面我们来定义一个单链表类型:

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

在完成了这一步之后,我们通常使用LinkList L 来定义一个链表L使用Lnode* p来定义一个结点指针p。接着我们对定义好了的单链表来进行初始化:

Status InitList_L(LinkList &L){
    L=new Lnode;        //给链表L分配内存空间
    L->next=NULL;       //初始化为一个空表
    return OK;
}

其中Status就表示一个数据类型,在我之前的博客里面关于顺序表的实现与操作中就有提到。Status后面的InitList_L就表示这个初始化函数的函数名,可以由我们自行定义,但最好是能够见名思意的。

三. 单链表的操作

1.判断链表是否为空

所谓空表就是链表中没有元素,但是头指针和头结点仍然存在。这个算法的核心思路就是判断头结点指针域是否为空,如下所示:

Status ListEmpty(LinkList L){
    if(L->next)    //表示不是空表,返回0
        return 0;
    else            //若是空表则返回1
        return 1;
}

其中,L->next就表示头结点的指针域,而我们的头指针则就是用L表示的

2. 单链表的销毁

就是从头指针开始,依次释放所有结点。所以可以利用一个循环来实现,循环结束的条件也就是指针指向空。表示没有结点可以再释放了。如下所示:

Status DestroyList_L(LinkList &L){
    Lnode* p;        //定义一个Lnode类型的指针p
    while(L){        //从头结点开始
        p=L;            
        L=L->next;    //指向下一个结点
        delete p;     //释放结点
     }
    return OK;
}

值得注意的是,我们类C语言中要想使用delete来释放一个空间,就得使用new来分配空间。

3. 单链表的清空

就是指链表仍然存在,但是链表中已经没有元素,成为了一个空链表(头指针和头结点仍然存在)

如下所示:

Status ClearList(LinkList &L){
    Lnode*p,*q;        //定义两个Lnode类型的指针
    p=L->next;        
    while(p){        //循环结束条件就是p指向空的时候
        q=p->next;
        delete p;
        p=q;
    }    
L->next=NULL;        //头结点指针域为空
return OK;
}

4. 求单链表的表长

        如下所示:

Status ListLength(LinkList L){
    LinkList p;
    p=L->next;    //p指向第一个结点
    i=0;
    while(p){        //遍历单链表,统计结点数
        i++;
        p=p->next;
    }
return i;
}
    

5. 单链表的取值

就是取单链表中第i个元素的内容。可以从链表的头指针出发,顺着链域next逐个结点往下搜索,直到搜索到第i个结点为止。因此,链表不是随机存取结构。

Status GetElem(LinkList L,int i,ElemType &e){
    Lnode* p;
    int j=1;
    p=L->next;
    while(p&&j<i){    //向后扫描,直到p为空或者指向到第i个元素为止
        p=p->next;
        ++j;
    }
if(!p||j>i) return ERROR;    //如果p指向空了或者j>i,表示链表中并没有这个元素
e=p->date;             //取第i个元素的数据,并通过e返回
return OK;
}

6. 单链表的查找

单链表的查找可分为两种,第一种就是根据指定数据获取该数据所在的位置(地址)。第二种则是根据指定数据获取该数据的位置序号。

如下所示,首先介绍第一种:

Lnode* LocateElem(LinkList L,ElemType e){
    p=L->next;
    while(p&&p->data!=e)
        p=p->next;
    return p;        //如果找到了就返回对应的地址,如果没找到,也就是p指向空的时候,返回NULL
}

第二种如下:

Status LocateElem(LinkList L,ElemType e){
    Lnode* p;
    p=L->next;    
    int j=1;
    while(p&&p->data!=e){
        p=p->next;
        j++
    }
if(p) return j;    //如果找到,返回L中值为e的数据元素的位置序号。
else return 0;    //否则返回0,表示没有找到
}

7. 单链表的插入

在第i个结点前插入值为e的新结点。核心思路就是使新结点的指针域指向结点a(i),使结点a(i-1)的指针域指向新结点。如下所示:

Status ListInsert(LinkList &L,int i,ElemType e){
    Lnode* p;
    p=L;
    int j=0;
    while(p&&j<i-1){    //寻找第i个结点,p指向i-1结点
        p=p->next;
        ++j
    }
if(!p||j>i-1) return ERROR;   //i大于表长+1或者小于1,插入位置非法
s=new Lnode;        //生成新结点s
s->data=e;        //新结点s的数据域为e
s->next=p->next;    //将结点s插入到L中去
p-next=s;
return OK;
}

8. 单链表的删除

就是删除第i个结点,如下所示:

Status ListDelete(LinkList& L,int i,ElemType &e){
    Lnode* p;
    p=L;
    int j=0;
    while(p->next&&j<i-1){    //寻找第i-1个结点,并让p指向它。
        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;
}

 

         

 

 

 

 

         

 

        

标签:结点,单链,Lnode,实现,next,链表,操作,指针
From: https://blog.csdn.net/2303_78660417/article/details/140711598

相关文章

  • 单链表的建立
    一.前言    单链表的建立一共有两种方法,一种是头插法,将元素插入在链表的头部,也叫前插法。另外一种则就是尾插法,将元素插入在链表尾部,也叫后插法。二.头插法    首先从一个空表开始,重复读入数据;接着生成新结点,将读入的数据存放到新结点的数据域当中;最后从......
  • es6中对数组的常用操作方法-普通数组
    参考https://www.jianshu.com/p/856f4200d3c0最近,经常操作数组,可是数组中的一些常用操作方法很迷糊,看了上面一篇文章之后,茅塞顿开。于是自己按照上面文章的用法,自己全部从头到尾写了一遍,分为普通的数组以及对象数组的操作。//定义数组constarr=[1,2,3,4,5]......
  • es6中对数组的常用操作方法-对象数组
    //定义对象数组constarrayObject=[{name:'name1',title:'title1'},{name:'name2',title:'title2'},{name:'name3',title:'title3'}];//数组对象......
  • 限时10分钟,你会怎么实现这段async/await代码?
    ......
  • GraalVM 静态编译下 OTel Java Agent 的自动增强方案与实现
    作者:望陶、铖朴随着OpenTelemetry在可观测领域影响力的不断提升,其项目以极快的速度不断演进。阿里云作为国内最广泛使用Java的厂商之一,深度参与OTelJava Instrumentation演进与社区活动,贡献、Review各类PR(pullrequest)合计超过100 余个,参与Issues讨论58个,在Op......
  • 实战篇-FPGA实现RGMII数据接收
        RGMII时序        前面讲到关于关于ARP的理论知识,该章节主要通过FPGA接收以太网数据,并作数据分析。    首先关于以太网RGMII接收时序如下图所示:                                 ......
  • 二叉树及其存储实现C语言(附上源码)
    1.什么是二叉树        二叉树是一种特殊的树型结构,其特点是每个结点至多只有两棵子树(即二叉树不存在度大于二的结点),并且二叉树的子树有左右之分,次序不可颠倒【有序树】。 2.二叉树的定义二叉树T:一个有穷的结点集合。    -这个集合可以为空;    -......
  • Nginx服务器无法实现伪静态化,在后台设置不成功
    错误提示:Nginx服务器无法实现伪静态化,在后台设置不成功解决方案:这主要是nginx的rewrite没有设置导致的在nginx.conf里找到网站的server配置段,一般我们推荐如下的配置     server {        listen          80;        server_name   ......
  • Python Selenium 操作链可以工作,但会停止我在 Firefox 中的程序
    我有时使用ActionsChains时遇到任何问题,今天它不起作用,你知道为什么吗?scrolling_bar=driver.find_element(By.CSS_SELECTOR,"#scrolling_bar")start=scrolling_bar.locationActionChains(driver)\.drag_and_drop_by_offset(scrolling_bar,start......
  • 操作系统杂项(十)
    目录一、简述socket中select、epoll的使用场景和区别1、使用场景2、区别二、epoll水平触发和边缘触发的区别三、简述Reactor和Proactor模式1、Reactor2、Proactor3、区别四、简述同步和异步的区别,阻塞和非阻塞的区别1、同步与异步2、阻塞与非阻塞五、简述BIO和NIO......