链表Linklist

发布时间:2023年12月17日
一、链表概念

链表也是线性表的一种,用于存取逻辑关系为线性的数据,但是和顺序表不同,链表的存储结构是链式存储,在内存中不连续,例如数据在内存中存储可能是下图:

要把链表的节点连接起来就需要通过指针来操作

所以在链表中,每个数据元素可以配有一个指针用于找到下一个元素即节点,这意味着,链表上的每个“元素”都长下图这个样子:

二、链表的特性

逻辑结构:线性结构??

存储结构:链式存储结构

特点:内存中不连续,通过指针链接

解决顺序表中的问题:长度固定和插入删除的麻烦

struct?node
{
????int?data;//数据域
????struct?node?*next;//指针域
}//

  • 单向链表

有头链表:存在一个头节点,(只作为链表开头,不存放数据)数据域无效,指针域有效。

无头链表:每一个节点的数据域和指针域都有效

1、遍历无头单向链表:

#include?<stdio.h>

typedef char?datatype;
typedef struct node
{
????datatype?data;     //数据域,用来存放数据。
    struct node *next; //指针域,用来存放下一个节点的地址。
} link_node_t, *link_list_t;
//?link_node_t?A;?等同于?struct?node?A;
//?link_list_t?p;?等同于?struct?node?*p;

int main(int?argc, char const *argv[])
{
    //1.定义4个节点
    link_node_t?A?= {'a', NULL};
    link_node_t?B?= {'b', NULL};
    link_node_t?C?= {'c', NULL};
    link_node_t?D?= {'d', NULL};

    //2.将四个节点连接起来
????A.next?= &B;
????B.next?= &C;
????C.next?= &D;

    //3.定义一个头指针,指向第一个节点。用于遍历链表。
    link_list_t?p?= &A;

    //4.遍历无头链表
    while (p?!= NULL)    //判断p所指是否为空,不为空则说明指向链表节点。
    {
        printf("%c?",?p->data); //打印节点中数据域
????????p?=?p->next;            //让p指向下一个节点
    }
    printf("\n");
    return 0;
}

2、遍历有头单向链表:

#include?<stdio.h>

typedef char?datatype;
typedef struct node
{
????datatype?data;     //数据域,用来存放数据。
    struct node *next; //指针域,用来存放下一个节点的地址。
} link_node_t, *link_list_t;
//?link_node_t?A;?等同于?struct?node?A;
//?link_list_t?p;?等同于?struct?node?*p;

int main(int?argc, char const *argv[])
{
    //1.定义4个节点
    link_node_t?A?= {'a', NULL};
    link_node_t?B?= {'b', NULL};
    link_node_t?C?= {'c', NULL};
    link_node_t?D?= {'d', NULL};

    //2.将四个节点连接起来
????A.next?= &B;
????B.next?= &C;
????C.next?= &D;

    //3.定义一个头节点,数据无效,指针域指向第一个节点。
    link_node_t?h?= {'\0', &A};

    //4.定义一个头指针,指向头节点。
    link_list_t?p?= &h;

    //5.遍历有头单项链表
#if?0
    //方法一:
????p?=?p->next; //跨过头节点,指向第一个节点。
    while (p?!= NULL)
    {
        printf("%c?",?p->data);
????????p?=?p->next;
    }
    printf("\n");
#else
    //方法二:
    while (p->next?!= NULL)
    {
????????p?=?p->next;
        printf("%c?",?p->data);
    }
    printf("\n");
#endif
    return 0;
}

链表尾插法练习:

写一个有头单项链表,用于保存输入的学生成绩,实现一输入学生成绩就创建一个新的节点,将成绩保存起来。再将该节点链接到链表的尾,直到输入-1结束。

要求:每个链表的节点由动态内存分配得到?,?也就是用malloc。

过程:

  1. malloc申请空间link_node_t大小作为头节点
  2. 将新节点放到链表尾部

先实现输入学生成绩,直到-1结束:

#include?<stdio.h>
typedef struct node_t
{
    int?score;
    struct node_t *next;
}link_node_t,* link_list_t;

int main(int?argc, char const *argv[])
{
    int?score?= -1;
    while (1)
    {
        scanf("%d", &score);
        if (score?== -1)
            break;
        
    }
    //1.malloc申请空间,创建一个新节点用于保存学生成绩。
    //2.将新节点链接到连表的尾部
    return 0;
}

继续实现malloc申请新节点存入学生成绩然后连接到链表尾部:

#include<stdio.h>
#include<stdlib.h>
typedef struct node_t
{
    int?score;
    struct node_t *next;
}link_node_t,*link_list_t;
int main(int?argc, char const *argv[])
{
    int?score?;
    link_list_t?pnew=NULL;//新节点地址指针
    link_list_t?ptail=NULL;//链表尾巴地址指针
    //1.malloc申请空间,创建一个新节点用于保存学生成绩。
    link_list_t?h=(link_list_t)malloc(sizeof(link_node_t)); //创建一个头节点,用头指针h指向头节点
    if(NULL==h)//判断成功开辟空间
    {
        perror("h?malloc?err");
        return -1;
    }
????h->score='\0';//头节点初始化
????h->next=NULL;
????ptail=h;//指向头节点
    //2、循环输入学生成绩,直到-1结束。并且新输入一个成绩创建一个新节点存入,然后把新节点链接到链表尾巴
    while (1)
    {
        scanf("%d",&score);
        getchar();
        if(score==-1)
        { 
           break;
        }
        else
        {
????????????pnew=(link_list_t)malloc(sizeof(link_node_t));//(1)创建一个新的节点用来保存输入学生成绩
????????????pnew->next=NULL;//新节点指针域赋空值
????????????pnew->score=score;//(2)对新节点的数据域和指针域进行赋值
????????????ptail->next=pnew;//(3)将新节点连接到链表尾部
????????????ptail=pnew;  //(4)链表延长一个新节点,需要将尾指针移动到新的节点作为尾巴
        }
    }
    //3.遍历有头链表
    while (h->next!=NULL)//判断p是否指向为空,若不为空则说明指向了下一个节点
    {
????????h=h->next;//将下一个节点地址赋值给p
        printf("%d?",h->score);
    }
    puts("?");
    return 0;
}
文章来源:https://blog.csdn.net/m0_74937538/article/details/132752042
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。