数据结构之链表节点的管理(基于C语言的实现)

在单链表中的一个节点,其结构由两部分构成,分别为数据域和指针域,数据域的数据类型可以为任意类型,用来存放当前节点需要存储的数据元素,可以是任意类型,指针域的数据类型是指针,用来存储下一个节点的地址,如果没有下一个节点,则指针域赋值NULL,节点的示意图如下:

链表具有如下优点:

克服数组链表需要预先知道数据大小的缺点;

链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理;

链表允许在任意位置上插入和删除节点;

 但是链表也存在一定的缺陷:

链表失去了数组随机存取的优点;

链表增加了指针域,使得其空间开销较大;

无法随机存取,存取元素时需要遍历链表,比较耗费时间;

本次将使用代码演示如何创建链表,以及对链表上节点的插入、删除、打印。 

代码展示:

List.c

#include <stdio.h>
#include <stdlib.h>
#include "List.h"

//创建一个带头结点的空单链表
//只有一个头结点,没有数据结点
List* CreateList(void)
{
    List *l = (List*) malloc(sizeof(List)) ;
    l->first = NULL;
    l->last = NULL;
}

/*
    Insert: 往带头结点的单链表l(升序),插入一个数据x
            要求插入后 l仍然升序
    @l: 头结点
    @x: 待插入的元素x
    返回值:
        无。
*/
void Insert(List* l, DataType x)
{
    if (l == NULL)
    {
        return ;
    }

    //创建一个“数据结点”,来保存x
    Node *p = (Node*) malloc(sizeof(Node));
    p->data = x;
    p->next = NULL;

    //把数据结点 p,插入到 l指向的链表中去。
    if (l->first == NULL)
    {
        l->first = p;
        l->last = p;
    }
    else
    {
        //1. 先找到插入位置
        // 从第一个数据结点开始,遍历,找到第一个值比p值大的结点 pk(及pk前面的那个结点pr),
        // pk的前面就是 插入位置
        Node *pk = NULL;//指向第一个值比p大的结点,“pk前面就是插入位置”
        Node *pr = NULL; //指向pk前面的那个结点

        pk = l->first;
        while (pk)
        {
            if (pk->data > p->data)
            {
                break;
            }

            pr = pk;
            pk = pk->next;
        }

        //2. 分情况完成插入操作

        if  (l->first->data > p->data )  // pr == NULL //(第一个结点就比p要大)
        {
            p->next = l->first;
            l->first = p;
        }
        else if (l->last->data < p->data) // pk == NULL //(链表上所有结点的值都比p要小)
        {
            l->last->next = p;
            l->last = p;
        }
        else //剩下的情况
        {
            // “中间插入”
            p->next = pk;
            pr->next = p;

        }

    }

}


//打印链表上每一个数据结点的值
void PrintList(List *l)
{
    if (l == NULL)
    {
        return ;
    }

    Node *p = l->first;
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
    }
}


/*
    DeleteX: 在一个链表l上,删除值为x的结点
    @l: 指向链表的头结点
    @x:要删除的结点的值
    返回值:
        无。
*/
void DeleteX(List*l, DataType x)
{
    if (l == NULL  || l->first == NULL)
    {
        return ;
    }


    // 1. 找要到删除的结点px
    Node *px ; //指向要删除的结点
    Node *pr; //指向 px前面的那个结点
    Node *ps = l->first; //每次查找的起始结点!!!

  
    while (1)
    {
        px = ps;
        while (px)
        {
            if (px->data == x)
            {
                break;
            }

            pr = px;
            px = px->next;
        }
        

        if (px == NULL) //没找到  要删除的结点
        {
            return;
        }

        ps = px->next; //下一次的查找起始结点应该是 px的下一个!!!

        // 2. 分情况完成删除操作
        if (px == l->first) //(删除的是第一个数据结点)
        {
            if (l->first == l->last)// (只有一个数据结点)
            {
                l->first = NULL;
                l->last = NULL;
                free(px);
            }
            else
            {
                l->first = px->next;
                px->next = NULL;
                free(px);
            }

        }
        else if (px == l->last) //(删除的是最后一个数据结点)
        {
            pr->next = NULL;
            l->last = pr;
            free(px);
        }
        else //删除的是中间结点
        {
            pr->next = px->next;
            px->next = NULL;
            free(px);
        }
    }

}


/*
    DeleteList: 删除整个链表
            要删除每一个数据结点,并且头结点也要删除
    @l: 头结点
    返回值:
        无。
*/
void DeleteList(List *l)
{
    if (l == NULL)
    {
        return ;
    }


    Node *px;

    //1. 删除所有的数据结点
    while (px = l->first)
    {
        l->first = px->next;
        px->next = NULL;
        free(px);
    }

    //2. 删除头结点
    free(l);


}

List.h

#ifndef __LIST_H__
#define __LIST_H__

typedef int DataType;

typedef struct Node
{
   DataType data;   // "数据域":保存数据元素的

   struct Node* next;    // "指针域":保存下一个数据元素的地址
}Node;


typedef struct List
{
   Node *first; //指向链表上的第一个“数据结点”
   Node *last ; //指向链表上的最后一个“数据结点”

   // ...
}List;

//创建一个带头结点的空单链表
//只有一个头结点,没有数据结点
List* CreateList(void);


/*
    Insert: 往带头结点的单链表l(升序),插入一个数据x
            要求插入后 l仍然升序
    @l: 头结点
    @x: 待插入的元素x
    返回值:
        无。
*/
void Insert(List* l, DataType x);


//打印链表上每一个数据结点的值
void PrintList(List *l);

/*
    DeleteX: 在一个链表l上,删除值为x的结点
    @l: 指向链表的头结点
    @x:要删除的结点的值
    返回值:
        无。
*/
void DeleteX(List*l, DataType x);


/*
    DeleteList: 删除整个链表
            要删除每一个数据结点,并且头结点也要删除
    @l: 头结点
    返回值:
        无。
*/
void DeleteList(List *l);

#endif

测试范例:

main.c



#include <stdio.h>

#include "List.h"


int main()
{
    int d;
    List *l = CreateList();

    while (1)
    {
        scanf("%d", &d);
        if (d == 0)
        {
            break;
        }


        Insert(l, d);
    }

    PrintList(l);
}   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值