线性表之双链表

本文介绍了双链表的基本概念及其实现方式,包括结构体定义、基本操作如插入、删除等,并通过示例代码展示了如何使用双链表进行数据管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

双链表实现

双链表是在单链表的基础上增加一个指向前一个节点的指针。使节点持有它前后两个节点指针。从而实现逆序遍历。
双链表的数据操作与单链表相差不大,只比单链表多修改一个指针,在插入和删除操作时要对首节点和最后一个节点特叔处理。具体实现见代码

结构体分析

先来看一下结构体的定义,如下,person的结构里只有数据域和两个前后节点,是最精简的了,没有多余数据。

    typedef struct person2{
        char name[10];
        int age;
        struct person2 *next;
        struct person2 *last;

}person2;

再来看linkedList结构体的定义。如下,这个结构体可以理解为是专门记录链表信息的管理型结构体,或者是专门操作person结构的工具。所以他持有链表头尾节点,表长。每条链表只含有有一个linkedList结构,或者说每一个linkedList代表一条链表。
这样linkedList里的数据就只有一份,空间复杂度O(1),已是最低了。
这里称linkedList里封装的head节点为头结点head,它的next指向链表第一个元素,称为首节点。所以头结点是不包含在链表上的,只是head节点的next指针指向首节点,end节点的last指针指向链表最后一个节点。

typedef struct linkedList{
    struct person2 *head;
    struct person2 *end;
    struct person2 *before;//先序遍历用的指针
    struct person2 *after;//后序遍历用的指针

    int length;
}linkedList;

实现代码如下:

//新建person
person2 *newP2(char *name,int age){


    //动态分配内存,初始化person
    person2 *p = (person2 *)malloc(sizeof(person2));
    p->age = age;
    strcpy(p->name,name);
    p->next = NULL;
    p->last = NULL;
    return p;
}

//建立空表
linkedList *newList(){

    //建立头结点
    linkedList *link = (linkedList *)malloc(sizeof(linkedList));

    //为头尾指针分配实体
    link->head = newP2("",-1);
    link->end = newP2("",-1);

    //使头尾互指 head->last和end->next 为null,
    link->head->next = link->end;
    link->end->last = link->head;

    link->after = link->end;
    link->before = link->head;
    link->length = 0;
    return link;
}

//add element in first
void addFirst(linkedList *link, person2 *p){
    person2 *head = link->head->next;

    //让新节点的next指向head->next
    p->next = head;

    //让head->next->last指向新元素
    head->last = p;


    //修改队首指针
    link->head->next = p;

    link->length++;

}

//add element in end
void addEnd(linkedList *link, person2 *p){

    person2 *end = link->end->last;

    //让新节点p的last指针指向最后一个元素end  让新元素p的last指向end->last;
    p->last = end;

     //让end 所指节点的next指针指向新节点p
    end->next = p;

    //修改队尾指针
    link->end->last = p;

    link->length++;

}

//根据index序号读表元素,返回数据域data(index序号按写入顺序,从0开始)
person2 *read(linkedList *link, int index){


    if(link->length > index && index >= 0 ){
        person2 *head =  link->head->next;

        int j = 0;

        while (head != NULL && j < index){
            head = head->next;
            j++;
        }
        if(j == index){
            return head;
        }
    }

    return NULL;
}

//定位元素 返回下标(从0开始)
int locatep2(linkedList *link, person2 *p){
    int i;
    person2 *head = link->head->next;

    for(i = 0; head != NULL; i++){
        if(compareP2(head,p)){
           return i;
        }
        head = head->next;
    }
    return -1;
}

//person 比较器
int compareP2(person2 *p1,person2 *p2){
    if(p1 == p2){
        return 1;
    }

    return (p1->age == p2->age && !strcmp(p1->name,p2->name));
}

//insert element before index
//实现思路:先找到index节点(调用read()),在修改指针。
void insertlink(linkedList *link,person2 *p,int index){

        person2 *p1;

        //得到要插入位置的元素
        if(index == 0 ){
            addFirst(link,p);
            return;
        }else if(index == link->length){
            addEnd(link,p);
            return;
        }else{
            p1 = read(link,index);
        }

        //insert element
        if(p1 != NULL){
            //新元素p的next指向index处元素p1
            p->next = p1;
            //新元素p的last指向index处元素p1的last
            p->last = p1->last;

            //修改插入位置两边的节点指向,使其指向新节点p(元素 == 节点,原谅我懒得改成统一)
            p1->last = p;
            p->last->next = p;

            link->length++;
        }else{
            printf("index not find");
            exit(1);
        }




}

//delete element by index
//实现思路:先找到index节点(调用read()),再修改指针。
void myRemove2(linkedList *link,int index){

         person2 *p1;

        if(index == 0 ){
            //指向第一个节点的head
            person2 *head = link->head;

            //待删除元素p1指向首节点
            p1 = head->next;

            //使head指向下下一个节点
            head->next = head->next->next;

            //使现在head的下一个元素的last指针为null(便于遍历元素)
            head->next->last = NULL;
        }
        else if(index == link->length-1){

            person2 *end = link->end;

            p1 = end->last;

            end->last = end->last->last;
            end->last->next = NULL;
        }
        else{    //不是首尾节点的情况
             //得到要插入位置的节点
            p1 = read(link,index);


        //delete element
            if(p1 == NULL){
                printf("index not find");
                exit(1);
            }

            p1->last->next = p1->next;
            p1->next->last = p1->last; 

        }
    free(p1);//一定要释放节点空间
    link->length--;
}

//先序遍历
person2 *before(linkedList *link){
    person2 *p = link->before->next;
    if(p != NULL){
        link->before = p;
        return p;
    }
    link->before = link->head;
    return NULL;
}

//后序遍历
person2 *after(linkedList *link){
    person2 *p = link->after->last;
    if(p != NULL){
        link->after = p;
        return p;
    }
    link->after = link->end;
    return NULL;
}

//print element
void linkPrint(linkedList *head){
    int length = head->length;
    person2 *begin = head->head->next;
    printf("***********length = : %d ************\n",length);

    for(;begin != NULL; begin = begin->next){
        printf("name: %s,age: %d\n",begin->name,begin->age);
    }

}

void doubleLinkMain(){
    //linkedList *p1;
    person2 *p2;


    //初始化 link list
    linkedList *head = newList();
    addEnd(head,newP2("HH",0));
    addEnd(head,newP2("HH",1));
    addEnd(head,newP2("HH",2));
    addEnd(head,newP2("HH",3));
    addEnd(head,newP2("HH",4));
    addEnd(head,newP2("HH",5));

    linkPrint(head);
    addFirst(head,newP2("ff",1));
    addFirst(head,newP2("ff",2));
    addFirst(head,newP2("ff",3));
    addFirst(head,newP2("ff",4));
    addFirst(head,newP2("ff",5));
    linkPrint(head);

    person2 *p1 = read(head,2);
    if(p1 != NULL){
        printf("read index 2 :%s++%d\n",p1->name,p1->age);
    }

    printf("found person(ff,2) index is %d\n",locatep2(head,newP2("ff",2)));

    //test insert element
    printf("insert element 0 ,4 \n");
    insertlink(head,newP2("new",66),0);
    insertlink(head,newP2("new",66),4);
    linkPrint(head);

    //test delete element
    printf("delete element 0 ,6, 12\n");
    myRemove2(head, 0);
    myRemove2(head, 6);
    myRemove2(head, 10);
    linkPrint(head);

    printf("\n\n");
    while((p2 = before(head)) != NULL){
        printf("先序遍历 :%s,%d\n",p2->name,p2->age);
    }
    while((p2 = after(head)) != NULL){
        printf("后序遍历 :%s,%d\n",p2->name,p2->age);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值