数据结构-双链表

笑着哭i 提交于 2020-12-16 03:24:53

数据结构:双链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点

双链表和单链表的区别

  • 单链表对于一个节点,有储存数据的data。和next后驱节点(指针)。也就是这个单链表想要一些遍历的操作都得通过前节点—>后节点。
  • 双链表对于一个节点,有些和单链表一样有存储数据的data,指向后方的next(指针)。它拥有单链表的所有操作和内容。但是他还有一个前驱节点front(指针)。
  • 单链表一般都有一个头结点,双向链表可以没有头结点。

本次创建的为一个没有头结点的双链表

双链表的创建

typedef struct dlinklist
{
    /*数据域*/
    int number;
    /*前驱指针*/
    struct dlinklist *front;
    /*后驱指针*/
    struct dlinklist *next;
}DLlinkList;

正因为拥有两个指针,所以双链表可以正向遍历也可以反向遍历。

双链表的初始化

DLlinkList* init_list(int n)
{
    int i;
    DLlinkList *head,*node,*end;

    if(n <= 0)
    {
        return NULL;
    }

    node = (DLlinkList*)malloc(sizeof(DLlinkList));
    scanf("%d",&node->number);
    head = node;
    end = node;
    for (i = 1; i < n; i++)
    {
        node = (DLlinkList*)malloc(sizeof(DLlinkList));
        scanf("%d",&node->number);
        end->next = node;
        node->front = end;
        end = node;
    }
    head->front = NULL;
    end->next = NULL;
    return head;
}

相比单链表,他们的操作基本一样,双链表多了前驱指针的操作。

增加节点

DLlinkList * add_node(DLlinkList *list, int n)
{
    DLlinkList *temp = list;
    DLlinkList *in;
    int i = 0;
    if (temp == NULL)
    {
        printf("list is empty!\n");
        return;
    }

    while (i < (n-1) && temp != NULL)
    {
        i++;
        temp = temp->next;
    }

    if (temp != NULL)
    {
        in = (DLlinkList*)malloc(sizeof(DLlinkList));
        scanf("%d",&in->number);
        if (temp->front == NULL)    /*头插*/
        {
            in->next = list;
            in->front = NULL;
            list = in;
        }
        else if (temp->next == NULL)    /*尾插*/
        {
            temp->next = in;
            in->front = temp;
            in->next = NULL;
        }
        else    /*中间插入*/
        {
            in->next = temp->next;
            in->front = temp;
            temp->next = in;
        }
    }
    else
    {
        printf("The %d node is empty,list has %d node\n",n,i);
    }
}

因为没有头结点,第一个节点可能会改变(头插时),所以返回值是一个节点的指针。

此函数包括了头插,尾插,和中间插入的逻辑。

删除节点

DLlinkList * del_node(DLlinkList *list, int n)
{
    DLlinkList *temp = list;
    DLlinkList *out;
    int i = 0;
    if (temp == NULL)
    {
        printf("list is empty!\n");
        return;
    }
    if (n <= 0)
    {
        printf("n is error!\n");
        return;
    }

    while (i < (n - 1) && temp != NULL)
    {
        i++;
        temp = temp->next;
    }

    if (temp != NULL)
    {
        if (temp->front == NULL)    /*删除头部*/
        {
            out = list;
            list = list->next;
            list->front = NULL;
        }
        else if (temp->next == NULL)    /*删除尾部*/
        {
            out = temp;
            out->front->next = NULL;
        }
        else    /*删除中间*/
        {
            out = temp;
            out->front->next = out->next;
            out->next->front = out->front;
            out = NULL;
        }
        
        free(out);
    }
    else
    {
        printf("The %d node is empty,list has %d node\n",n,i);
    }
    return list;
}

删除节点和增加节点一样,包含了三个逻辑:删除头,删除尾,删除中间

修改节点

void modify_num(LINKLIST *list,int n)
{
    LINKLIST *temp = list;
    int i = 0;
    if (temp == NULL)
    {
        printf("list is empty!");
        return;
    }

    while (i < n && temp != NULL)
    {
        i++;
        temp = temp->next;
    }

    if (temp != NULL)
    {
        scanf("%d",&temp->number);
    }
    else
    {
        printf("the %d node is empty!\n",n);
    }

修改节点比较简单,遍历修改number就可以

输出双链表

void printf_list(DLlinkList *list)
{
    DLlinkList *temp = list;
    if (temp == NULL)
    {
        printf("list is empty!");
        return;
    }

    if (temp->front == NULL && temp->next == NULL)  /*只有一个节点*/
    {
        printf("list number:%d\n",temp->number);
        return;
    }
    else if (temp->front == NULL)   /*从头部开始*/
    {
        while (temp != NULL)
        {
            printf("list number:%d\n",temp->number);
            temp = temp->next;
        }
    }
    else
    {
        while (temp != NULL)    /*从尾部开始*/
        {
            printf("list number:%d\n",temp->number);
            temp = temp->front;
        }
    }
    
    return;
}

输出操作包含了从头部输出和从尾部输出两个逻辑

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!