c语言:双向链表

108 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第28天,点击查看活动详情

前言

以前参与一个蓝牙电话本的项目,不同的手机实现的电话簿关键字各个不同,测试的人会加上几十万的联系人,所以一个排序和链表是必不可少的。当初用一个单向链表保存了全部的联系人,本人尝试实现双向链表数据结构。

接口

一个简单的结构图如下所示

image.png 许多链表的实现上,头节点作为起始节点,不存在有效数据;有的实现上头节点作为实际有效的节点。但在实现上和可理解程度上,头节点单纯作为起始节点,代码实现会更简单,代码会少许多麻烦,比起浪费一个节点的空间缺点来说,值得。

结构体

typedef struct LL{
    struct LL *fNode;
    struct LL *nNode;
}DUALIST ,*DUALISTPtr;

typedef struct{
    DUALISTPtr CuNode;
    int key;
    int var ;
}MYLST,*MYLSTPtr;

接口:

  1. 新节点添加链表头 Add2Head
  2. 新节点添加链表尾 Add2Tail
  3. 删除节点,接口主键使用的整数 DelNode
  4. 修改数据, ChgVal
  5. 清空链表 ClearLst
  6. 遍历节点,我一般用来打印全部信息 IterateLst

代码实例

想着按照Linux内核链表实现方案,把链表结构和应用数据结构做结解耦,提出一些接口,应用数据部分结构随意更改。
无奈个人水平太差,查找功能接口如何和链表方案的解耦方案不会。所以实例代码里链表结构和应用数据在一起实现。
这样逻辑,此链表少了许多通用型,过些日子再回来修改,继续优化一点。

#include<stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

typedef void (*func)(int a,int b);

typedef struct LL{
    struct LL *fNode;
    struct LL *nNode;
    int key;
    int var ;
}MYLST,*MYLSTPtr;


#define INITLIST(v,t) do{ v = (t*)malloc(sizeof(t));memset(v,0,sizeof(t));v->fNode = v->nNode = v; }while(0)

int Add2Head(MYLSTPtr Hd,MYLSTPtr v)
{
    MYLSTPtr tt = Hd;
    MYLSTPtr tt2 = v;

    //修改原第二节点和新点的相互指向
    tt2->nNode = tt->nNode;
    tt->nNode->fNode = tt2;
    //修改头节点和新点的相互指向
    tt2->fNode = tt;
    tt->nNode = tt2;
    return 0;
}
int Add2Tail(MYLSTPtr Hd,MYLSTPtr v)
{
    MYLSTPtr Head = Hd;
    MYLSTPtr NewNd = v;

    //修改原尾节点和新点的相互指向
    Head->fNode->nNode = NewNd;
    NewNd->fNode = Head->fNode;

    //修改头节点和新点的相互指向
    NewNd->nNode = Head;
    Head->fNode = NewNd;
    return 0;
}
int DelNode(MYLSTPtr Hd,int key)
{
    MYLSTPtr Head = Hd;
    MYLSTPtr FirNode =  Head->nNode;
    int ret = 0;
    while(FirNode != Head){
        FirNode = FirNode->nNode;
        if(key == FirNode->key){
            FirNode->nNode->fNode = FirNode->fNode;
            FirNode->fNode->nNode = FirNode->nNode;
            free(FirNode);
            ret = 1;
            break;
        }
    }
    return ret;
}
int ChgVal(MYLSTPtr Hd,int key,int val)
{
    MYLSTPtr Head = Hd;
    MYLSTPtr FirNode =  Head->nNode;
    int ret = 0;
    while(FirNode != Head){
        FirNode = FirNode->nNode;
        if(key == FirNode->key){
            FirNode->var = val;

            ret = 1;
            break;
        }
    }    return 0;
}
int ClearLst(MYLSTPtr Hd)
{
    MYLSTPtr temp = Hd;
    Hd->fNode->nNode = NULL;
    while(Hd){
        temp = Hd;
        Hd = Hd->nNode;
        free(temp);
    }
    return 0;
}

//dir= 1 正向
//dir= 0 反向
int IterateLst(MYLSTPtr Hd,func fPtr,int dir)
{
    MYLSTPtr Head = Hd;
    MYLSTPtr FirNode = dir==1? Head->nNode:Head->fNode;
    while(FirNode != Head){
        if(fPtr) fPtr(FirNode->key,FirNode->var);
        FirNode = dir==1? FirNode->nNode:FirNode->fNode;
    }
    return 0;
}

void printfall(int key, int val)
{
    printf("key[%d] val[%d]\n",key,val);
}

int main(int argc, char** argv)
{
    int cnt = 0;
    MYLSTPtr Head;
    INITLIST(Head,MYLST);

    MYLSTPtr MyNode = NULL;
    while(cnt < 100){
        MyNode  = (MYLSTPtr)malloc(sizeof(MYLST));
        MyNode->key = MyNode->var = cnt;
        MyNode->fNode = MyNode->nNode = NULL;
        Add2Head(Head,MyNode);
        cnt++;
    }
    IterateLst(Head,printfall,1);
    ClearLst(Head);
    Head = NULL;
    return 0;
}

测试结果

image.png