双向链表的创建(C语言)

双向链表的相对于单向链表,更加方便,应因为它指针域里有前面结点的地址。

//
// Created by liujun on 2022/4/16.
//

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

typedef struct data{
    int num;            //数据域:存放数据
    struct data *prev;  //前驱指针:指向前一个节点的地址
    struct data *next;  //后继指针:指向下一个节点的地址
}Data;

/*
函数功能:
    创建一个头节点,并将头节点的地址返回
返回值:
    成功:返回一片地址
    失败:返回NULL
*/
Data *request_head_node(void)
{
    Data *head = (Data *)malloc(sizeof(Data));
    if(head == NULL)
    {
        printf("malloc head fail\n");
        return NULL;
    }
    head->prev = NULL;
    head->next = NULL;
    return head;
}

/*
函数功能:
    传入数据,给这个数据申请一个新节点来存放
参数:
    data_num:要存放的数据
返回值:
    申请好的新节点的地址
*/
Data *request_new_node(int data_num)
{
    Data *new = (Data *)malloc(sizeof(Data));
    if(new == NULL)
    {
        printf("malloc new node fail\n");
        return NULL;
    }

    new->num = data_num;//将传入的数据存放到新节点的数据域
    new->prev = NULL;//让前驱指针指向NULL,还没有加入链表
    new->next = NULL;//让后继指针指向NULL,还没有加入链表
    return new;
}

/*
函数功能:
    头插法插入节点,将新节点插入到头节点后一个节点
参数:
    head:要被插入的链表的头节点
    new:要插入链表的新节点
*/
void inset_to_head(Data *head,Data *new)
{
    //先改变要插入的节点的指针域
    new->prev = head;
    new->next = head->next;
    //再改变要插入位置的前后节点的指针域
    if(head->next != NULL)//如果只有头节点,就不需要解引用头节点的下一个节点,不然就是解引用NULL
    {
        head->next->prev = new;
    }
    head->next = new;
}

/*
函数功能:
    打印链表中的所有数据
参数:
    head:链表的头节点
*/
void show_list(Data *head)
{
    Data *p = NULL;
    //因为头节点不存放数据,不用打印头节点内容
    for(p=head->next;p!=NULL;p=p->next)
    {
        printf("%d\t",p->num);
    }
    printf("\n");
}

/*
函数功能:
    将新节点插入到链表尾部
参数:
    head:要被插入的链表的头节点
    new:要插入的节点
*/
void inset_to_last(Data *head,Data *new)
{
    //找到尾节点
    Data *p = NULL;
    for(p=head;p->next!=NULL;p=p->next);
    //将新节点插入到尾节点后面

    new->prev = p;
    p->next = new;
}

/*
函数功能:
    根据传入的数据来查找存放了这个数据的节点
参数:
    head:链表头节点
    find_num:要查找的数据
返回值:
    成功:返回找到的节点
    失败:返回NULL
*/
Data *find_node(Data *head,int find_num)
{
    Data *p = NULL;
    for(p=head->next;p!=NULL&&p->num!=find_num;p=p->next);//查找节点
    return p;
}

/*
函数功能:
    根据传入的数据,删除对应的节点
参数:
    head:链表头节点
    delete_num:要删除的节点里的数据
返回值:
    成功:返回0
    失败:返回-1
*/
int delete_node(Data *head,int delete_num)
{
    Data *p = find_node(head,delete_num);
    if(p != NULL)//p不为NULL就说明p就是要删除的节点
    {
        Data *prev = p->prev;//用prev记录下p的前一个节点

        prev->next = p->next;//让p前一个节点的后继指针指向p的后面
        if(p->next != NULL)//如果p不是最后一个节点,说明它后面还有节点
        {
            p->next->prev = prev;//让p的后一个节点的前驱指针指向p的前一个节点
        }//p就被脱离出了链表
        p->prev = NULL;//保险起见,清空脱离节点的指针域
        p->next = NULL;
        free(p);
        return 0;
    }
    return -1;
}

/*
函数功能:
    删除一条链表
参数:
    head:要删除的链表的头节点
*/
void remove_list(Data *head)
{
    Data *p = NULL;//指向要删除的节点
    for(p=head->next;head->next!=NULL;p=p->next)
    {
        //让头节点的下一个指向要删除节点的下一个
        head->next = p->next;
        free(p);
    }
    //循环结束,只剩一个头节点,再头节点释放
    free(head);
}

int main(int argc, char const *argv[])
{

    //申请链表的头节点
    Data *head = request_head_node();
    Data *new = NULL;

    int n;
    while(1)
    {
        scanf("%d",&n);
        if(n == 0)
        {
            break;
        }
        if(n > 0)
        {
            new = request_new_node(n);
            inset_to_last(head,new);
        }
        if(n < 0)
        {
            delete_node(head,0-n);
        }
        /*
        if(n < 0)
        {
            Data *find = find_node(head,0-n);
            if(find != NULL)
            {
                printf("find node is %d\n",find->num);
            }
            else
                printf("没有这个节点\n");
        }
        */
        show_list(head);
    }

    remove_list(head);


    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值