有头节点的单链表

前言

头节点:链表的第一个节点,该节点的数据域一般不存放数据
首元节点:头节点后边的第一个节点
头指针:指向第一个元素所在的节点
单链表中可以没有头结点,但是不能没有头指针!

实现功能

  1. 有头节点的空链表的创建
  2. 指定位置插入节点
  3. 按大小顺序插入节点
  4. 删除下标为i的节点
  5. 删除某个节点
  6. 查询链表是否为空
  7. 打印链表
  8. 销毁链表

程序源码

/*有头节点的单链表*/
#include <stdio.h>
#include <stdlib.h>

/*类型重定义,方便以后修改变量类型*/
typedef int datatype; 
typedef struct node_st
{
    datatype data;        //数据域
    struct node_st *next;  //指针域
}list;

/*函数声明*/
list *list_create();                                  //创建只有头节点的空链表
int list_insert_at(list *head, int i,datatype *data); //指定位置插入
int list_order_insert(list *head,datatype *data);     //按顺序插入
int list_delete_at(list *head,int i,datatype *data);  //删除下标为i的元素
int list_delete(list *head,datatype *data);           //删除某个元素
int list_isempty(list *head);                         //检查链表是否为空
void list_display(list *head);                        //打印链表
void list_destroy(list *head);                        //销毁链表

int main()
{
    int i = 0,sz,ret;
    datatype arr[] = {4,3,2,1,0};
    list *head;            //定义头指针

    sz = sizeof(arr)/sizeof(*arr); //数组元素个数
    head = list_create();  //创建空链表,返回头指针
    if(head == NULL)       //创建失败则退出程序
    {
        exit(1);
    }
    printf("链表的插入\n");
    for(i=0;i<sz;i++)
    {
    //  ret = list_insert_at(head,0,&arr[i]);  //按指定位置插入元素
        ret = list_order_insert(head,&arr[i]); //按顺序插入元素
        if(ret != 0)
        {
            exit(1);
        }
    }
    list_display(head);     //打印链表

    printf("删除某个节点\n");
    int value1  = 2;
    list_delete(head,&value1);  //删除某个元素
    list_display(head);


    printf("删除i位置的节点\n");
    datatype value2,err;
    err = list_delete_at(head,0,&value2);//删除0号节点
    if(err)
    {
        exit(1);
    }
    list_display(head);
    printf("delte:%d\n",value2);  //被删除节点的值

    list_destroy(head);     //销毁链表

    return 0;
}

/*函数定义*/
//创建只有头节点的空链表
list *list_create()
{
    list *head;         //定义结构体指针变量
    head = malloc(sizeof(*head)); //申请内存空间,大小为list结构体

    if(head == NULL)     //申请内存失败
    {
        return NULL;
    }
    head->next = NULL;   //头节点的指针域设为空,数据域不管

    return head;        //返回空链表的结构体指针(头指针)
}

//指定位置插入
int list_insert_at(list *head, int i,datatype *data)
{
    //计数方式:不包括头节点,第一个有效节点从0开始
    int j = 0;
    list *p = head;  //使用p代替head进行后面操作
    list *q;
    if(i < 0)   //下标有误,i要>=0
    {
        return -1;
    }
    
    //找i-1位置的原因:单向链表只能往一个方向遍历,
    //若p指针指向的是i位置的节点,那么就无法知道i位置的前驱是哪个节点
    //若p指针指向的是i-1位置的节点,就可以知道i位置的前驱就是i-1节点的后继
  
    /*寻找i位置的前驱节点*/
    while(j<i && p->next!=NULL)//从第1个有效节点开始,寻找i-1位置,当i=0时,首部插入
    {
        p = p->next;  //p指向下一个节点
        j++;
    }
    if(p)   //p不为空指针
    {
        q = malloc(sizeof(*q));//为新节点申请内存空间
        if(q == NULL)
        {
            return -2;
        }
        q->data = *data;  //新节点的数据域
        //q->next = NULL;  //指针域暂时为空

        q->next = p->next;  //p,q的指针域指向同一个后继节点
        p->next = q;        //使q成为p的后继节点

        return 0;
    }
    else   //找不到
    {
        return -3;
    }
}

/*按升序插入元素*/
int list_order_insert(list *head,datatype *data)  //按顺序插入
{
    list *p = head,*q;

    /*寻找数据域>=*data的前驱节点*/
    //p->next为空时,说明空链表或p指向尾节点
    //p->next->data < *data:p节点的下一个节点的数据域小于*data
    while(p->next && p->next->data < *data)
    {
        p = p->next;  //结构体指针p指向下一个节点
    }
    q = malloc(sizeof(*q));  //为新节点申请内存空间
    if(q==NULL)       //申请内存失败
    {
        return -1;
    }
    // 原先: 1 2  p  5    
    //插入后:1  2  p  q  5
    q->data = *data;    //新节点q的数据域存放*data
    q->next = p->next;  //将节点p的指针域赋值给q的指针域,此时p和q的指针域都指向了同一节点 
    p->next = q;        //将节点p的指针域指向q,此时p的指针域指向了q,所以q成为p的后继节点      

    return 0;
}

//删除下标为i的元素,*data为删除的节点的数据
int list_delete_at(list *head,int i,datatype *data)
{
    int j = 0;
    list *p = head,*q;

    if(i<0)  //下标有误,i>=0
    {
        return -1;
    }
    /*寻找i-1处的节点*/
    //p->next==NULL时,p指向了空链表或p指向了尾节点
    while(j<i && p->next)
    {
        p = p->next;
        j++;
    }
    if(p->next)  //p不是尾节点(空链表)
    {
        //要删除q节点:q的前驱指向q的后继,跳过q
        q = p->next;      //使p成为q的前驱节点
        p->next = q->next;//q的前驱指向q的后继
        *data  = q->data; //返回要删除的数值

        free(q);
        q = NULL;
        return 0;
    }
    else
    {
        return -2;
    }
}

//删除某个元素
int list_delete(list *head,datatype *data)
{
    list *p = head,*q;
    /*寻找数据域是*data的前驱节点*/
    while(p->next && p->next->data != *data)
    {
        p = p->next;
    }
    if(p->next == NULL)//链表为空或p是尾节点,没找到
    {
        return -1;
    }
    else   //找到了,删除q节点
    {
        q = p->next;       //使p成为q的前驱节点
        p->next = q->next; //q的前驱节点指向q的后继节点
        free(q);           //释放内存空间
        q = NULL;
    }
}

//链表是否为空
int list_isempty(list *head)
{
    if(head->next==NULL)
        return 0;
    return 1;     //不为空
}

//打印链表
void list_display(list *head)
{
    list *node = head->next;//第1个有效节点,头节点的数据域不用

    if(list_isempty(head)==0)
        return ;

    while(node != NULL)
    {
        printf("%d  ",node->data);
        node = node->next;
    }
    printf("\n");
    return ;
}

//销毁链表
void list_destroy(list *head)
{
    list *node,*next_node;
    for(node=head->next;node!=NULL;node=next_node)
    {
        next_node = node->next;
        free(node); //销毁有效节点
    }
    free(head);  //销毁头节点

    return ;
}

程序运行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是带有头节点单链表的创建、插入、删除、查找的 C 语言代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct ListNode { int val; struct ListNode *next; } ListNode; // 创建一个带有头节点链表,并返回头节点指针 ListNode *createList() { ListNode *head = (ListNode *) malloc(sizeof(ListNode)); head->next = NULL; return head; } // 在链表尾部插入一个值为val的新节点 void insert(ListNode *head, int val) { ListNode *newNode = (ListNode *) malloc(sizeof(ListNode)); newNode->val = val; newNode->next = NULL; ListNode *p = head; while (p->next != NULL) { p = p->next; } p->next = newNode; } // 在链表中删除第一个值为val的节点 void delete(ListNode *head, int val) { ListNode *prev = head; ListNode *curr = head->next; while (curr != NULL && curr->val != val) { prev = curr; curr = curr->next; } if (curr != NULL) { prev->next = curr->next; free(curr); } } // 在链表中查找第一个值为val的节点,并返回该节点指针 ListNode *search(ListNode *head, int val) { ListNode *p = head->next; while (p != NULL && p->val != val) { p = p->next; } return p; } int main() { ListNode *head = createList(); // 插入节点 insert(head, 1); insert(head, 2); insert(head, 3); // 查找节点 ListNode *p = search(head, 2); if (p != NULL) { printf("Found node with value %d\n", p->val); } else { printf("Node not found\n"); } // 删除节点 delete(head, 2); // 再次查找节点 p = search(head, 2); if (p != NULL) { printf("Found node with value %d\n", p->val); } else { printf("Node not found\n"); } return 0; } ``` 这里的代码示例中,我们定义了一个链表节点结构体 `ListNode`,包含一个整数值 `val` 和一个指向下一个节点的指针 `next`。我们使用 `createList` 函数创建一个带有头节点链表,并返回头节点指针。使用 `insert` 函数在链表尾部插入一个新节点,使用 `delete` 函数删除第一个值为 `val` 的节点,使用 `search` 函数查找第一个值为 `val` 的节点,并返回该节点的指针。在主函数中,我们通过插入、查找、删除节点来演示链表的基本操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

⁽⁽ଘ晴空万里ଓ⁾⁾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值