双链表--list

数据结构 – 双链表



一. 原理

说明:双链表和单链表的区别在于,单链表只有一个指向下一节点的指针,双链表有两个,既可以指向上一节点,也可以指向下一节点,表现为:

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

原理图:
在这里插入图片描述
在这里插入图片描述

二. 定义

分别申请节点结构体 和 首位结构体:

typedef struct node{
    int data;
    struct node* next;
    struct node* prev;
}node_t;

typedef struct list{
    struct node head; //可以不用指针
    struct node tail; //
}list_t;

三. 常见双链表操作

1. 链表初始化

void list_init(list_t *list)
{
    list->head=(node *)malloc(sizeof(node_t));//申请内存
    list->tail=(node *)malloc(sizeof(node_t));//申请内存
    list->head.prev=NULL;
    list->tail.next=NULL;
    list->head.next=&(list->tail); // 首尾相接
    list->tail.prev=&(list->head);
}

2. 创建双链表节点

node_t *creat_node(int data)
{
    note_t *ptemp=(node_t *)malloc(sizeof(node_t));  // malloc
    ptemp->data=data;
    ptemp->prev=NULL;
    ptemp->next=NULL;
    return ptemp;
}

3. 插入节点-之间

说明:在任意两个节点之间插入新的节点;
static void insert_data(node_t *pfirst,node_t *pmid, node_t *pnode)
{
    pfirst->next=pnode;
    pnode->prev=pfirst;
    pnode->next=pmid;
    pmid->prev=pnode;
}

4. 插入节点-前插

说明:在头结点和第一个节点之间插入;
/*前插*/
void list_add_head(list_t *list,int data)
{
    //创建节点
    node_t *pnode=creat_node(data);
    //创建游标
    node_t *pfirst=&list->head;//head地址
    node_t *pmid=pfirst->next;//第一个节点
    node_t *plast=pmid->next;//第二个
    //在pfirst和pmid之间插入节点
    insert_data(pfirst,pmid, pnode);//插入
}

5. 插入节点-后插

说明:在最后一个节点和尾部节点之间插入节点,使用 游标法;
void list_add_tail(list_t *list,int data)
{
    //创建节点
    node_t *pnode=creat_node(data);
    //创建游标
    node_t *pfirst=list->tail.prev;//最后一个节点
    node_t *pmid=pfirst->next;//指向tail
    node_t *plast=pmid->next;//指向NULL
    //在pfirst和pmid之间插入节点
    insert_data(pfirst,pmid, pnode);//插入
}

6. 插入节点-从大到小

说明:游标法判断节点大小; 
void list_add(list_t *list,int data)
{
    //创建节点
    node_t *pnode=creat_node(data);
    //创建游标
    for(node_t *ptmp =&list->head;ptmp != &list->tail; ptmp=ptmp->next){
        node_t *pfirst=ptmp;//head地址
        node_t *pmid=pfirst->next;//第一个节点
        node_t *plast=pmid->next;//第二个
        if(pmid->data > pnode->data || pmid == &list->tail){
                insert_data(pfirst,pmid, pnode);//插入
                break;//必须中断,否则后面遇见大的又要插入
        }                
    }
}

7. 删除节点

 说明:切记既然malloc了,释放就一定得free,否则持续占用内存;
static void del_data(note_t *pfirst, note_t *pmid, note_t *plast)
{
    //链接pfirst和plast,干掉pmid
    pfirst->next=plast;
    plast->prev=pfirst;
    free(pmid);
    pmid=NULL;    
}

8. 查找并删除节点

//删除某个字所在节点
void list_del(list_t *list,int data)
{
    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);        
        }            
    }
}

9. 注销整个双链表

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->next = plast;
             plast->pre =pfirst;
             //干掉pmid节点的内存
             free(pmid);
             pmid=NULL;       
        }
    
}

总结:

  1. 双链表日常语法如上,简易理解;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值