超详细最全数据结构个人笔记【单向链表】

1.链表基本概念

链式存储的线性表,简称链表

链表其实是由一个或者多个结构体通过指针指向的关系构成
我们把每个结构体的变量称为节点,节点里面由两个成员组成
一个是数据域,另外一个是指针域,指针域是用于存放下一个节点的地址
以此类推,我们把这种存储方式称为链式存储

2.链表与顺序表差异

​ 既然顺序存储中的数据因为挤在一起而导致需要成片移动,那很容易想到的解决方案是将数据离散地存储在不同内存块中,然后在用来指针将它们串起来。这种朴素的思路所形成的链式线性表,就是所谓的链表。

顺序表和链表在内存中基本状态如图所示:

在这里插入图片描述

3.链表的分类

​ 根据链表中各个节点之间使用指针的个数,以及首尾节点是否相连,可以将链表细分为如下种类:

  1. 无头节点单向链表(LinkedList.c)
  2. 有头节点单向链表(LinkedListWithHead.c)

在这里插入图片描述

  1. 双向链表(BothwayLinkedList.c)
  2. 循环链表(LoopLinkedList.c)

这些不同的链表的操作都是差不多的,只是指针数目的异同。以最简单的单向链表为例,其基本示意图如下所示:

在这里插入图片描述

上图中,所有的节点均保存一个指针,指向其逻辑上相邻的下一个节点(末尾节点指向空)。另外注意到,整条链表用一个所谓的头指针 head 来指向,由 head 开始可以找到链表中的任意一个节点。head 通常被称为头指针

链表的基本操作,一般包括:

  1. 节点设计
  2. 初始化空链表
  3. 增删节点
  4. 链表遍历
  5. 销毁链表

4.无头节点单链表节点设计

// 节点
struct node
{
	int data; //数据域 
    // 指针域,指向下一个节点(存放下一个节点的地址)
	struct node *next; 
};

在这里插入图片描述

5.节点的空间分配

​ 1.栈空间 : 过了生命周期自动释放

​ 2.堆空间: malloc只需要保存地址即可,生命周期与程序保持一致

6.创建链表步骤

​ **1. 从无到有:**第一个节点的诞生,此时的首节点和尾节点都是它本身

2 .从少到多(添加节点过程):

1. 在原来链表的后面添加新节点(尾插法)

​ 新节点接在尾节点后面,即尾节点指向新节点,原来的尾节点被新节点替代

​ 特点 : 新接入的节点在前面,后接入的节点在后面

2.在原来的链表的前面添加新节点(头插法)

​ 新节点接在原来链表的首节点前面,即新的节点指向原来的首节点,然后首节点被新节点替代

​ 特点:后接入的节点在前面,先接入的节点在后面

7.学习链表方法:

​ 一定要自己学会画图分析,再把思路转为代码,其实写代码要逻辑清晰才能写的快,切记你是怎么思考的就怎么写,没思考清除前别着急写。

demo:

​ 1.创建新节点

// 创建新节点
struct node *create_newNode(dataType data)
{
    struct node *pnew = malloc(sizeof(struct node));
    if(pnew == NULL)
        return NULL;

    // 将新数据写入到新节点
    pnew->data = data;
    pnew->next = NULL;
    return pnew;
}

2.创建新链表

// 创建新链表
struct node *create_list()
{
    dataType data;
    // 新节点指针,用于指向新节点
    struct node *pnew = NULL;
    // 指向首节点指针
    struct node *head = NULL;
    // 指向尾节点指针
    struct node *tail = NULL;

    while(1)
    {
        scanf("%d",&data);
        if(data == 0)
            break;
        
        // 创建新节点
        pnew = create_newNode(data);
        if(pnew == NULL)
        {
            perror("create newNode failed:");
            return NULL;
        }

        // 将新节点插入到链表
        if(head == NULL)// 从无到有,此时首节点和尾节点都是pnew
        {
            head = pnew;
            tail = pnew;
        }
        else // 从少到多
        {
            tail->next = pnew;
            tail = pnew;// 更新尾节点
        }
    }
    return head;
}


3.打印信息

// 打印信息
void showList(struct node *head)
{
    for(struct node *p = head; p != NULL; p = p->next)
        printf("%d  ",p->data);
    printf("\n");
}

练习:

​ 1.实现头插法

​ 2.实现链表的修改节点和删除节点

​ 3.实现链表数据在任意位置添加

8.带头节点的单向链表

1.图解

在这里插入图片描述

// 定义数据节点
struct node
{
	dataType data; // 数据域
	struct node *next; // 指针域,存放(指向)下一个节点的地址
};
//-----------------------------------

// 定义头节点
struct headNode
{
	struct node *first; // 指向第一个数据节点
	struct node *last; // 指向最后一个数据节点
	int nodeNumber; // 记录链表节点数
};

demo:

创建头节点

struct headNode* create_new_headNode()
{
    struct headNode* head =  malloc(sizeof(struct headNode));
    if(head == NULL)
        return NULL;
    head->first = NULL;
    head->last = NULL;
    head->nodeNumber = 0;
    return head;
}

创建数据节点

// 创建新节点
struct node* create_new_node(dataType data)
{
    struct node* pnew =  malloc(sizeof(struct node));
    if(pnew == NULL)
        return NULL;
    pnew->data = data;
    pnew->next = NULL;
    return pnew;
}

尾插法

// 尾插法
void addTail(struct headNode *head,struct node* pnew)
{
    head->last->next = pnew;
    head->last = pnew;
}

创建链表

struct headNode* create_list()
{
    // 创建头节点
    struct headNode* head = create_new_headNode();
    if(head == NULL)
        return NULL;
    
    dataType data = -1;

    while(1)
    {
        scanf("%d",&data);
        if(data == 0)
            break;
        // 创建新节点
        struct node* pnew = create_new_node(data);
        if(pnew == NULL)
            return NULL;

        // 从无到有
        if(head->first == NULL)
        {
            head->first = pnew;
            head->last = pnew;
        }
        else // 从少到多
        {
            // 尾插法
            addTail(head,pnew);
        }
        // 更新节点
         head->nodeNumber++;
    }

    return head;
}

显示链表

void showList(struct headNode* head)
{
    if(head->first == NULL)
    {
        printf("链表为空\n");
        return;
    }
    for(struct node* p = head->first;p != head->last->next;p = p->next)
    {
        printf("%d\t",p->data);
    }
    printf("\n");
    printf("链表节点数为:%d\n",head->nodeNumber);
}
  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值