C语言数据结构(DAY03)

7.数据结构之双链表

双链表每个节点的结构体

struct node {
	数据;
	struct node *next; // 保存下一个节点的首地址
	struct node *prev; // 保存上一个节点的首地址
};

参见图:双链表.png

在这里插入图片描述

参考代码:list2.c

/*双链表演示*/
#ifndef __LIST_H
#define __LIST_H

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

/*声明描述节点信息的结构体*/
typedef struct node {
    int data; //数据
    struct node *next; //指向下一个节点
    struct node *prev; //指向上一个节点
}node_t;

/*声明描述整个链表的结构体*/
typedef struct list {
    struct node head; //头节点
    struct node tail; //尾节点
}list_t;

/*声明初始化链表函数*/
extern void list_init(list_t *);
/*清理链表函数*/
extern void list_deinit(list_t *);
/*判断链表是否为空,空返回1,非空返回0*/
extern int list_empty(list_t *);
/*获取链表节点个数*/
extern int list_size(list_t *);
/*后插*/
extern void list_add_tail(list_t *, int);
/*前插*/
extern void list_add_head(list_t *, int);
/*小->大插*/
extern void list_add(list_t *, int);
/*只删除第一个节点*/
extern void list_del_head(list_t *);
/*只删除最后一个节点*/
extern void list_del_tail(list_t *);
/*删除某个数字所在的节点*/
extern void list_del(list_t *, int );
/*只获取第一个节点数据*/
extern int list_get_head(list_t *);
/*只获取最后一个节点数据*/
extern int list_get_tail(list_t *);
/*通过节点编号获取节点数据*/
extern int list_get(list_t *, int);
#endif

#include "list.h"

/*定义初始化链表函数*/
/*空链表:head和tail连起来*/
void list_init(list_t *list)
{
    list->head.next = &list->tail; //头指向尾
    list->tail.prev = &list->head; //尾指向头
    list->head.prev = NULL;
    list->tail.next = NULL;
}

/*判断链表是否为空*/
int list_empty(list_t *list)
{
    return list->head.next == &list->tail; //空返回1,非空返回0
}

/*获取链表节点个数*/
int list_size(list_t *list)
{
    int count = 0; //计数
    for(node_t *pnode = &list->head; 
            pnode != &list->tail; pnode = pnode->next) {
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid != &list->tail)
            count++; //只要没有到tail,加一个
    }
    return count;
}

//定义创建节点函数
static node_t *create_node(int data)
{
    //给节点分配内存
    node_t *p = (node_t *)malloc(sizeof(node_t));
    //初始化节点
    p->next = NULL;
    p->prev = NULL;
    p->data = data;
    return p;
}

//定义将新节点插入pfirst和pmid之间
static void insert_data(node_t *pfirst, node_t *pmid, node_t *pnode)
{
    //将新节点插入pfirst和pmid之间
    pfirst->next = pnode;
    pnode->prev = pfirst;
    pnode->next = pmid;
    pmid->prev = pnode;
}

/*后插*/
void list_add_tail(list_t *list, int data)
{
    //创建新节点
    node_t *pnode = create_node(data); 
    //定义游标:随意定游标,这个代码仅仅参考
    node_t *pfirst = list->tail.prev; //pfirst指向最后一个节点
    node_t *pmid = pfirst->next; //pmid指向tail
    node_t *plast = pmid->next; //plast指向NULL
    //插入
    insert_data(pfirst, pmid, pnode);
}

/*前插*/
void list_add_head(list_t *list, int data)
{
    //创建新节点
    node_t *pnode = create_node(data); 
    //定义游标 
    node_t *pfirst = &list->head; //pfirst指向head
    node_t *pmid = pfirst->next; //pmid指向第一个节点
    node_t *plast = pmid->next; //plast指向第二个节点
    //插入
    insert_data(pfirst, pmid, pnode);
}

/*由小到大插*/
void list_add(list_t *list, int data)
{
    //1.创建新节点
    node_t *pnode = create_node(data);
    //2.遍历
    for(node_t *ptmp = &list->head; 
            ptmp != &list->tail; ptmp = ptmp->next) {
        //3.游标
        node_t *pfirst = ptmp;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        //4.将新节点同样插入到pfirst和pmid之间
        if(pmid->data > pnode->data || pmid == &list->tail) {
            insert_data(pfirst, pmid, pnode); //插入
            break;
        }
    }
}

//删除节点
static void del_data(node_t *pfirst, node_t *pmid, node_t *plast)
{
    //1.连接pfirst和plast,干掉pmid
    pfirst->next = plast;
    plast->prev = pfirst;

    //2.释放pmid的内存
    free(pmid);
    pmid = NULL;
}

/*删除最后一个节点*/
void list_del_tail(list_t *list)
{
    //1.判断是否空链表
    if(list->head.next == &list->tail) {
        printf("链表空了.\n");
        return;
    }

    //2.定义游标
    node_t *plast = &list->tail; //plast指向tail
    node_t *pmid = plast->prev; //pmid指向最后一个节点
    node_t *pfirst = pmid->prev; //pfirst指向倒数第二个节点

    //3.删除数据
    del_data(pfirst, pmid, plast);
}

/*删除第一个节点*/
void list_del_head(list_t *list)
{
    /*1.判断链表是否为空*/
    if(list_empty(list)) {
        printf("链表空了.\n");
        return;
    }

    //2.定义游标
    node_t *pfirst = &list->head; //pfirst指向头节点
    node_t *pmid = pfirst->next; //pmid指向第一个节点
    node_t *plast = pmid->next; //plast指向第二个节点

    //3.删除数据
    del_data(pfirst, pmid, plast);
}

/*删除某个数字所在的节点*/
void list_del(list_t *list, int data)
{
    //通过data遍历遍历找到要删除的节点pmid
    for(node_t *pnode = &list->head; 
            pnode != &list->tail; pnode=pnode->next) {
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        if(pmid->data == data && pmid != &list->tail) {
            //删除数据
            del_data(pfirst, pmid, plast);
        }
    }
}

/*获取最后一个节点的数据并返回*/
int list_get_tail(list_t *list)
{
    //判断链表是否为空
    if(list_empty(list))
        return -1;

    //定义游标
    node_t *plast = &list->tail; //plast指向tail
    node_t *pmid = plast->prev; //pmid指向最后一个节点
    node_t *pfirst = pmid->prev; //pfirst指向倒数第二个节点

    //返回pmid指向的最后一个节点中的数据
    return pmid->data;
}

/*获取第一个节点的数据并返回*/
int list_get_head(list_t *list)
{
    //判断链表是否为空
    if(list_empty(list))
        return -1;

    //定义游标
    node_t *pfirst = &list->head; //pfirst指向head
    node_t *pmid = pfirst->next; //pmid指向第一个节点
    node_t *plast = pmid->next; //pfirst指向第二个节点

    //返回pmid指向的第一个节点中的数据
    return pmid->data;
     
}

/*根据节点编号获取对应的数据*/
int list_get(list_t *list, int index)
{
    //1.计数
    int count = 0;

    //2.找节点
    for(node_t *pnode = &list->head;
            pnode != &list->tail; pnode=pnode->next) {
        //3.定义游标
        node_t *pfirst = pnode;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        //4.判断count和index
        if(count == index && pmid != &list->tail) {
            return pmid->data;
        }
        count++;
    }
    return -1; //没有找到
}

/*清理链表*/
void list_deinit(list_t *list)
{
    while(list->head.next != &list->tail) {
        //定义游标
        node_t *pfirst = &list->head;
        node_t *pmid = pfirst->next;
        node_t *plast = pmid->next;
        
        //先连接pfirst和plast
        pfirst->next = plast;
        plast->prev = pfirst;

        //干掉pmid节点的内存
        free(pmid);
        pmid = NULL;
    }
}

#include "list.h"

int main(void)
{
    //1.创建链表
    list_t list;

    //2.初始化链表
    list_init(&list);

    //3.前插
    list_add_head(&list, 50); //50
    list_add_head(&list, 20); //20 50
    
    //4.后插
    list_add_tail(&list, 70); //20 50 70
    list_add_tail(&list, 100); //20 50 70 100
    
    //5.小到大插
    list_add(&list, 80);
    list_add(&list, 30);
    list_add(&list, 40);
    list_add(&list, 60);
    list_add(&list, 90);
    list_add(&list, 10);
    
    //6.获取节点个数
    int size = list_size(&list);
    printf("节点个数为%d\n", size);

    //7.打印节点数据
    for(int i = 0; i < size; i++) {
        printf("%d ", list_get(&list, i));        
    }
    printf("\n");

    //8.获取第一个节点数据
    printf("第一个节点数据是%d\n", list_get_head(&list));
    //9.获取最后一个节点数据
    printf("最后一个节点数据是%d\n", list_get_tail(&list));
    //10.删除第一个节点
    list_del_head(&list);
    //11.删除最后一个节点
    list_del_tail(&list);
    //12.删除50所在的节点
    list_del(&list, 50);
    //13.打印节点数据
    for(int i = 0; i < list_size(&list); i++) {
        printf("%d ", list_get(&list, i));        
    }
    printf("\n");
    //14.清理
    list_deinit(&list);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值