数据结构:双向链表

一、基本概念

        解决顺序存储的缺点,插入和删除,动态存储(在编写代码阶段,不需要预估存储的大小,内存使用率较高)问题。

特点:
    线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素,存储单元可以是连续的,也可以不连续。可以被存储在任意内存未被占用的位置上。
    
    所以前面的顺序表只需要存储数据元素信息就可以了。在链式结构中还需要一个元素存储下一个元素的地址。
    
    为了表示每个数据元素,ai与其直接后继数据元素ai+1之间的逻辑关系,对ai来说,除了存储其本身的信息外,还需要存一个指示器直接后续的信息。把存储元素信息的域叫数据域,把存储直接后继位置的域叫指针域。这两部分信息组成数据元素ai的存储映像,叫结点(Node);

二、基本函数

单链表中,c语言的描述
typedef struct person {
    char name[32];
    char sex;
    int age;
    int score;
}DATATYPE;

typedef struct node {
    DATATYPE data;
    struct node *next,*prev;
}LinkNode;

typedef struct list {
    LinkNode *head;
    int tlen;//元素总结点个数
    int clen;//当前链表里结点个数
}LinkList;

1.DouLinkList* CreateDouLinkList();
2.int InsertHeadLinkList(DouLinkList *list, DATATYPE *data);
3.int ShowDouLinkList(DouLinkList *list,DIRECT direct);
4.int GetSizeDouLinkList(DouLinkList *list);
5.int RevertDouLinkList(DouLinkList *list);
6.DouLinkNode *FindLinkList(DouLinkList *list, PFUN fun,void* arg);
7.int DeleteLinkList(DouLinkList *list, PFUN fun,void* arg);
8.int IsEmptyDouLinkList(DouLinkList *list);
9.int ModifyDouLinkList(DouLinkList *list,PFUN fun,void* arg,DATATYPE *data);
10.int DestroyDouLinkList(DouLinkList **list);
11.int InserPosDouLinkList(DouLinkList *list,DATATYPE *data,int pos);

1. CreateDouLinkList  创建双向链表

DouLinkList *CreateDouLinkList()
{
    DouLinkList* dl = (DouLinkList*)malloc(sizeof(DouLinkList));
    if(NULL == dl)
    {
        perror("CreateDouLinkList malloc");
        return NULL;
    }
    dl->head =NULL;
    dl->clen = 0 ;

    return dl;
}

 2. InsertHeadDouLinkList  头插

int InsertHeadLinkList(DouLinkList *list, DATATYPE *data)
{
    DouLinkNode*newnode = malloc(sizeof(DouLinkNode));
    if(NULL == newnode)
    {
        perror("InsertHeadLinkList malloc");
        return 1;
    }
    memcpy(&newnode->data,data,sizeof(DATATYPE));
    newnode->next = NULL;
    newnode->prev= NULL;

    if(0==list->clen)//empty
    {
        list->head = newnode;
    }
    else
    {
        newnode->next = list->head;
        list->head->prev = newnode;
        list->head = newnode;
    }
    list->clen++;
    return 0;
}

 3. ShowDouLinkList 打印

xxx.h

typedef enum{DIR_FORWARD,DIR_BACKWARD}DIRECT;

xxx.c

int ShowDouLinkList(DouLinkList *list, DIRECT direct)
{
    int i = 0 ;
    DouLinkNode* tmp = list->head;
    if(direct==DIR_FORWARD)
    {
        for(i=0;i<GetSizeDouLinkList(list);i++)
        {
            printf("%s %c %d %d\n",tmp->data.name,tmp->data.sex,tmp->data.age,tmp->data.score);
            tmp=tmp->next;
        }
    }
    else
    {
        while(tmp->next)
        {
            tmp=tmp->next;
        }
        for(i=0;i<GetSizeDouLinkList(list);i++)
        {
            printf("%s %c %d %d\n",tmp->data.name,tmp->data.sex,tmp->data.age,tmp->data.score);
            tmp=tmp->prev;
        }
    }
    return 0;
}

(注意:如果是头插的方式,选择顺序打印,打印的效果是相反的)

4. GetSizeDouLinkList 获取当前元素个数 

int GetSizeDouLinkList(DouLinkList *list)
{
    return list->clen;
}

 5.RevertDouLinkList  逆序

 逆序前准备:

逆序具体操作:


int RevertDouLinkList(DouLinkList *list)
{
    int size = GetSizeDouLinkList(list);
    if(size<2)
    {
        return 0;
    }

    DouLinkNode* prev= NULL;
    DouLinkNode* tmp = list->head;
    DouLinkNode*next= tmp->next;
    while(1)
    {
        tmp->next = prev;
        tmp->prev = next;
        prev= tmp;
        tmp = next;
        if(NULL == tmp)
        {
            break;
        }
        next =next->next;
    }
    list->head = prev;
    return 0;
}

6. FindDouLinkList 查找 

 xxx.h

typedef int (*PFUN)(DATATYPE*data,void* arg);

xxx.c

DouLinkNode *FindLinkList(DouLinkList *list, PFUN fun, void *arg)
{
    DouLinkNode* tmp = list->head;
    int size = GetSizeDouLinkList(list);
    int i =  0;
    for(i = 0 ;i<size;i++)
    {
        //if(0==strcmp(tmp->data.name))
        if(fun(&tmp->data,arg))
        {
            return tmp;
        }
        tmp= tmp->next;
    }
    return NULL;
}

main.c

int findbyname(DATATYPE*data,void* arg)
{
    return (0 == strcmp(data->name,(char*)arg));
}
int findbyage(DATATYPE*data,void* arg)
{
    return data->age == *(int*)arg;
}


int main()
{
    DATATYPE data[5]={
        {"zhangsan",'m',20,70},
        {"lisi",'f',21,60},
        {"wangmazi",'m',25,80},
        {"liubei",'f',30,85},
        {"caocao",'f',40,90},
    };
    char want_name[]="lisi";
    DouLinkNode* tmp = FindLinkList(dl,findbyname,want_name);
    int want_age = 25;
    DouLinkNode* tmp = FindLinkList(dl,findbyage,&want_age);
    if(NULL == tmp)
    {
        printf("can't find person ,name:%s\n",want_name);
    }
    else
    {
       printf("%s:%d\n",tmp->data.name,tmp->data.score);
    }
    return 0;
}

7. DeleteDouLinkList 删除链表中某个结点

 xxx.h

int DeleteLinkList(DouLinkList *list, PFUN fun,void* arg);

xxx.c

int DeleteLinkList(DouLinkList *list, PFUN fun, void *arg)
{
    if(NULL == list)
    {
        fprintf(stderr,"DouLinkList is null");
        return 1;
    }
    if(IsEmptyDouLinkList(list))
    {
        fprintf(stderr,"DouLinkList is empty");
        return 1;
    }
    DouLinkNode* ret = FindLinkList(list,fun,arg);
    if(NULL==ret)
    {
        fprintf(stderr,"DeleteLinkList error,cant find\n");
        return 1;
    }
    if(ret == list->head)
    {
        list->head = ret->next;
        list->head->prev = NULL;
    }
    else
    {
        if(ret->next)
        ret->next->prev = ret->prev;
        ret->prev->next = ret->next;
    }

    free(ret);
    list->clen--;
    return 0;
}

main.c

int findbyname(DATATYPE*data,void* arg)
{
    return (0 == strcmp(data->name,(char*)arg));
}
int findbyage(DATATYPE*data,void* arg)
{
    return data->age == *(int*)arg;
}

int main()
{
    DATATYPE data[5]={
        {"zhangsan",'m',20,70},
        {"lisi",'f',21,60},
        {"wangmazi",'m',25,80},
        {"liubei",'f',30,85},
        {"caocao",'f',40,90},
    };

    DeleteLinkList(dl,findbyname,"lisi");
    return 0;
}

8.  IsEmptyDouLinkList 判断链表元素是否为空

int IsEmptyDouLinkList(DouLinkList *list)
{
    return 0 == list->clen;
}

9. ModifyDouLinkList 修改结点内容

 xxx.h

typedef int (*PFUN)(DATATYPE*data,void* arg);
int ModifyDouLinkList(DouLinkList *list,PFUN fun,void* arg,DATATYPE *data);

xxx.c

int ModifyDouLinkList(DouLinkList *list, PFUN fun, void *arg, DATATYPE *data)
{
    DouLinkNode* ret = FindLinkList(list,fun,arg);
    if(NULL == ret)
    {
        fprintf(stderr,"ModifyDouLinkList error,cant find\n");
        return 1;
    }
    memcpy(&ret->data,data,sizeof(DATATYPE));
    return 0;
}

main.c

int findbyname(DATATYPE*data,void* arg)
{
    return (0 == strcmp(data->name,(char*)arg));
}
int findbyage(DATATYPE*data,void* arg)
{
    return data->age == *(int*)arg;
}

int main()
{
    DATATYPE data[5]={
        {"zhangsan",'m',20,70},
        {"lisi",'f',21,60},
        {"wangmazi",'m',25,80},
        {"liubei",'f',30,85},
        {"caocao",'f',40,90},
    };

    ModifyDouLinkList(dl,findbyname,"zhangsan",&data[3]);
    return 0;
}

10. DestroyDouLinkList  销毁链表

int DestroyDouLinkList(DouLinkList **list)
{
    DouLinkNode* tmp=(*list)->head;
    while(tmp)
    {
    (*list)->head=(*list)->head->next;
    free(tmp);
    tmp = (*list)->head;

    }
    free(*list);
    (*list)= NULL;
    return 0;
}

11.  InserPosDouLinkList 随机位置插入结点

xxx.h

int InserPosDouLinkList(DouLinkList *list,DATATYPE *data,int pos);

 xxx.c

int InserPosDouLinkList(DouLinkList *list, DATATYPE *data,int pos)
{
    if(pos<0 ||pos>GetSizeDouLinkList(list))
    {
        fprintf(stderr,"InserPosDouLinkList error,index error\n");
        return 1;

    }
    if(IsEmptyDouLinkList(list) || 0 == pos)
    {
        return InsertHeadLinkList(list,data);
    }
    else
    {
        DouLinkNode* tmp = list->head;
        tmp= list->head;
        DouLinkNode* newnode = (DouLinkNode*)malloc(sizeof(DouLinkNode));
        if(NULL == newnode)
        {
            perror("InserPosDouLinkList malloc");
            return 1;
        }
        memcpy(&newnode->data,data,sizeof(DATATYPE));
        newnode->prev = NULL;
        newnode->next = NULL;
        int i = pos-1;
        while(i--)
        {
            tmp=tmp->next;
        }
        newnode ->prev = tmp;
        newnode->next = tmp->next;

        if(tmp->next)
        {
        tmp->next->prev = newnode;
        }
        tmp->next = newnode;
    }
    list->clen++;
    return 0;
}

main.c

int main()
{
    DATATYPE data[5]={
        {"zhangsan",'m',20,70},
        {"lisi",'f',21,60},
        {"wangmazi",'m',25,80},
        {"liubei",'f',30,85},
        {"caocao",'f',40,90},
    };

    InserPosDouLinkList(dl,&data[3],3);
    return 0;
}

三、顺序表和链表 优缺点

    存储方式:
        顺序表是一段连续的存储单元
        链表是逻辑结构连续物理结构(在内存中的表现形式)不连续
    
    时间性能:
        查找  顺序表O(1)
                 链表  O(n)
        插入和删除
                 顺序表 O(n)
                 链表   O(1)
            
    空间性能
            顺序表,需要预先分配空间,大小固定
            链表,不需要预先分配,大小可变,动态分配            
            
    循环链表
        简单的来说,就是将原来单链表中最有一个元素的next指针指向第一个元素或头结点,链表就成了一个环,头尾相连,就成了循环链表。circultlar linker list        
        注意非空表,和空表。多数会加入头结点。
        原来结束的条件是
        p->next != NULL ------->>>>> 此时遍历结束条件:p->next != Head 
        
    双向链表
    double link list。    
    typedef struct DulNode
    {
        ElemType date;
        struct DulNode *pri;
        sturct DulNode *next;
    }DulNode,*DuLinkList;

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值