数据结构(线性结构:单链表)

上一篇博客讲解了数据结构中的线性结构的一个最简单的结构,顺序结构,本篇文章来讲解稍微复杂点的的结构,单链表。

顺序结构类似于一种结构数组,在一个结构中有一个数组,数组中存放数据,因此一个结构可以存放多个元素。而单链表类似于带有指针的结构体。一个结构只存放一个元素,但是结果与结构之间使用指针相连,构成了一个线性的结构。单链表结构如图所示:

 头结点指向表中的第一个结构,一般头结点不存储元素,每个结构中存储一个元素,指针指向下一个后继节点。第一个存储元素的结构成为首结点,最后一个结构成为尾结点,尾结点指针为空。头结点指向首结点,并且单链表一直从头结点开始,一直到最后一个尾结点。

单链表结构定义如下:

#include <stdio.h>
#include <malloc.h>

typedef char elemtype;       //定义数据类型;
typedef struct LNode
{
    elemtype data;           //用来存放数据
    struct LNode *next;      //指针指向后继节点
}LinkNode;

在单链表的一些基本操作和顺序表相似,有建立,销毁初始化等操作,但是执行起来却大不相同。在单链表中的操作有:

1.建立单链表

建立单链表的基本操作就是插入结点。将一个新的节点插入到单链表中。例如我们要将结点s插入到节点L后面,基本操作为,先让节点s的后继指针指向L后继指针所指的结点,在将L的后继指针指向s。如图所示:

初始时,结点s不在表中

 先将s的后继节点的指针指向L后继节点的指针所指向的结点:如图

 在将L后继节点的指针指向s:如图

 最后结点成功插入:

代码实现如下:

s->next=L->next;   //将L的后继节点赋给s;
L->next=s;         //将L的后继节点定义为s;

以数组a[n]中的元素为基准建立单链表。其中建立单链表的方式有两种,一种是头插法,另一种是尾插法。头插法是先提取a[i],在建立新节点,从表头开始依次插入结点,而尾插法则是把每个元素都插在表尾。

头插法建立单链表相对简单,直接插在元素头结点后面就可以完成对单链表的建立,代码实现如下:

void CreateListF(LinkNode *&L,elemtype a[],int n)
{
    int i=0;
    LinkNode *p;                                  //定义新节点p;
    L=(LinkNode*)malloc(sizeof(LinkNode));        //将要建立的单链表L置为空,在依次插如元素
    L->next=NULL;
    while(i<n)                                 
    {
       p=L=(LinkNode*)malloc(sizeof(LinkNode));   //给p分配存储节点,在将a[i]的值赋给p;
       p->data=a[i];
       p->next=L->next;                           //将p插入L中
       L->next=p;
    }
}

如图,将新的节点插在头结点后面,将其他结点“挤”到后面,依次插入,最后建立完成。

尾插法建立单链表相对较复杂,通过一个结点指向单链表的尾结点,将要插入的结点插在该元素后面,插入一个新元素之后,该结点向后移动一位,重新指向新的尾元素。

代码实现如下:

void CreateListR(LinkNode *&L,int a[],int n)
{
    LinkNode *p,*q;
    L=(LinkNode*)malloc(sizeof(LinkNode));    //将L置为空,依次插入元素
    L->next=NULL
    p=L;                                      //指针p指向L;
    for(int i=0;i<n;i++)
    {                                         
        q=(LinkNode*)malloc(sizeof(LinkNode));//给q分配存储空间,将数组的值赋给q的元素值
        q->data=a[i];
        q->next=p->next;                      //将q插入p的后面;
        p->next=q;  
        p=q;                                  //p指向尾结点;
    }
}

如图,指针p始终指向尾结点,插入元素时直接插在p指向的结点后面,依次插入,建立完成。

2.销毁单链表

该操作相对简单,通过定义两个指针p,pre,pre指向单链表的首结点,p指向首结点的后继节点,先释放掉pre,在将pre指向p的后继节点,将p指向pre的后继节点,在删除pre,依次进行删除释放,最后销毁整个单链表。

代码实现如下:

void DestroyList(LinkNode *&L)
{
    LinkNode *pre=L,*p=L->next;    //pre指向首结点结点,pre指向首结点的后继节点
    while(p!=NULL)
       {
           free(pre);              //销毁首结点
           pre=p;                  //此时新的首结点为p,在将pre指向新的首结点
           p=pre->next;            //p指向首结点的后继节点
       }
    free(pre);                     //删除尾结点,销毁完成
}

如图所示:

3.初始化单链表

初始化线性表指建立一个空的单链表,相当于建立一个头结点为空的单链表。直接将头结点置为空之后就可以完成改操作。代码实现如下

void InitList(LinkNode *&L)
{
     L=(LinkNode*)malloc(sizeof(LinkNode));
     L->next=NULL;                //创建头结点并置为空
}

4.输出单链表

要逐一输出单链表,必须要有一个指针逐一扫描单链表,在将扫描到的元素值依次输出,由于头结点没有不存储元素,因此我们用首结点开始扫描。代码实现如下。

void DispList(LinkNode *L)
{
     char e;
     LinkNode *p=L->next;       //将指针p指向首结点,相当于头结点的后继节点。
     while(p!=NULL)             //如果p不为空,将该节点则输出。
         {
              e=p->data;
              printf("%c",e);
              p=p->next;       //输出之后转移到下一个节点
         }
     printd("\n");
}

5. 求单链表长度

在顺序表中,直接输出顺序表的长度即可。但是在单链表中,没有记录具体的长度,需要通过“数鸭子”一样的方式依次“数”出单链表的长度。同样,先定义一个指针p,让指针p指向首结点,并且记录,在将指针p向后移动,继续记录,直到p为空。代码实现如下:

int ListLength(LinkNode *&L)
{
     int i=0;                //定义一个基本整形i,将i赋值为0;
     LinkNode *p=L->next;    //将指针p指向首结点。
     while(p!=NULL)          //若p不为空,表示有节点,i加上一位
     {
         i++;
         p=p->next;          //p向后转移一位。
     } 
     return (i);             //最后返回i;
}

6.求单链表中的某个元素值

要求单链表中的某个位置的元素值,首先应该找到改位置,然后在“读取”里面的元素值。例如,若要求出单链表中第i个元素的元素值。应该先用一个指针依次扫描并记录,直到扫描到第i个元素。代码实现如下:

bool GetElem(LinkNode *L,int i,ElemType &e)
{
     int j=1;                  //从第一个元素开始记录,将j定义为1
     LinkNode *p=L->next;      //p指向首结点
     if(i<=0)
        return false;          //如果i为0,则无法查找,返回错误
     while(j<i&&p!=NULL)       //向后依次记录元素的个数
         {
             j++;
             p=p->next;
         }
     if(p==NULL)              //若p为空,则单链表没有第i个元素,返回错误。
        return false;
     else                     //找到之后将i赋给e,返回为真,查找完成。
        {
           e=p->data;
           return true;
        }
}

7.按元素查找

查找单链表中一个与值域相等的元素,同样,需要扫描单链表,如存在,则将该位置返回,不存在则返回0,代码实现如下:

int LocateElem(LinkNode *L,elemtype e)
{
     int i=1;
     LinkNode *p=L->next;         //p指向首结点
     while(p!=NULL&&p->data!=e)   //如果p值域不为e,i加1,p向后移动一位
       {
           i++;
           p=p->next;
       }
     if(p==NULL)                  //若p为空,则单链表中无该元素,返回0
        return 0;
     else                         //若p不为空,则将i返回
        return i;
}

8.将数据元素插入指定的位置

将数据元素elemtype e插入单链表L的第i个位置,首先在单链表中找到第i-1个结点,然后在插入到该结点的后面,代码实现如下:

bool ListInsert(LinkNode *L,int i,elemtype e)
{
     int j=1;
     LinkNode *p,*q;
     p=L->next;
     while(j<i&&p!=NULL)         //从头结点开始依次查找第i个元素
     {
         j++
         p=p->next
     }
     if(p==NULL)                //未找到则返回错误
        return false;
     else                       //找到之后建立新的节点,再将新的节点插入,操作完成
      {
         q=(LinkNode*)malloc(sizeof(LinkNode));
         q->data=e;
         q->next=p->next;
         p->next=q;
         return true;
      }
}

9.删除第i个结点,并将该结点用e返回

该运算实现的过程是找到第i-1个结点,直接将第i-1个结点的指针指向第i的结点的后继节点,在释放第i个结点,运算完成,代码实现如下:

bool ListDelete(LinkNode *&L,int i,elemtype &e)
{
    int j=1;
    LinkNode *p,q;
    p=L->next;
    while(j<i-2&&p!=NULL)           //找到第i-1个元素。
       {
           j++;
           p=p->next;
       }
     if(p==NULL)                  //若没找到,则返回错我
       return false;
     else
       {                           //找到之后,如下一个元素为空,也返回错我。
           q=p->next;
           if(q==NULL)
              return false;
           e=q->data;           //若不为空,则将第i个元素的值赋给e。
           p->next=q->next;    //将第i-1个元素的指针指向第i个元素的后继节点
           free(p);          //释放第i个元素,返回真
           return true;
       }
}

单链表的基本操作已经讲解完成,若有不足和错误之处,欢迎大家在评论区指出,谢谢。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值