【数据结构--双向链表】

1、双向链表的概念

  双向链表也叫双向表,是链表的一种,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点。

image.png

  与访问单向链表一样对于双向链表的访问也需要使用头指针。

image.png

2、双向链表的结点

typedef struct DuLNode
{
    ElemType data;
    struct DuLNode *pre; //指向前驱结点的指针
    struct DuLNode *next; //指向后继结点的指针
}DuLNode, *DuLinkList;

3、双向链表的初始化

DuLinkList list_init()
{
    DuLinkList head;
    //创建一个头结点,使用head指针指向头结点(头指针)
    head = (DuLinkList)malloc(sizeof(DuLNode));
    head->next = NULL;
    head->pre = NULL;
    return head;
}

4、双向链表头插法

image.png

/*
 * @brief 双向链表头插法
 * @param head 双向链表头指针
 * @param pTail 双向链表尾指针地址
 * @param data 需要插入的元素的值
 * @return 成功返回TRUE 失败返回FALSE
 * */
int head_insert(DuLinkList head, DuLNode **pTail, ElemType data)
{
    if (NULL == head)
    {
        printf("[%s %d] head pointer is NULL ...\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    //创建一个新的结点
    DuLNode *p = (DuLNode *)malloc(sizeof(DuLNode));
    p->pre = NULL;
    p->next = NULL;
    p->data = data;
​
    //如果链表为空
    if (NULL == head->next)
    {
        //第一个插入的结点就是尾结点
        *pTail = p;
        head->next = p;
        return TRUE;
    }
​
    p->next = head->next;
    head->next = p;
    return TRUE;
}
 

5、双向链表从头结点开始打印

//从头结点开始打印
void print_list_from_head(DuLinkList head)
{
    if (NULL == head)
        return;
​
    DuLNode *t = head->next;
    while (t != NULL)
    {
        printf("%d ", t->data);
        t = t->next;
    }
    printf("\n");
}

6、双向链表从尾结点开始打印

//从尾结点开始打印
void print_list_from_tail(DuLNode *tail)
{
    if (NULL == tail)
        return;
​
    DuLNode *t = tail;
    //一直遍历到头结点
    while (t->pre != NULL)
    {
        printf("%d ", t->data);
        t = t->pre; //向前开始遍历
    }
    printf("\n");
}

7、双向链表尾插法

image.png

 

8、双向链表在指定的位置插入结点

image.png

/*
 * @brief 在双向链表指定位置插入一个结点
 * @param head 双向链表头指针
 * @param index 需要插入的位置
 * @param data 需要插入的元素的值
 * @return 成功返回TRUE 失败返回FALSE
 * */
int insert_by_index(DuLinkList head, uint index, ElemType data)
{
    if (NULL == head)
    {
        printf("[%s %d] head point is NULL\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    int i = 1;
    DuLNode *t = head->next;
​
    while (i < index && t != NULL)
    {
        i++;
        t = t->next;
    }
​
    if (NULL == t)
    {
        printf("[%s %d] index out of range ...\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    //创建一个新的结点
    DuLNode *p = (DuLNode *)malloc(sizeof(DuLNode));
    p->pre = NULL;
    p->next = NULL;
    p->data = data;
​
    p->next = t;
    p->pre = t->pre;
    t->pre->next = p;
    t->pre = p;
​
    return TRUE;
​
}

9、双向链表插入一个结点保持原链表为升序

/*
 * @brief 双向链表插入一个结点保持原链表为升序
 * @param head 双向链表头指针
 * @param pTail 双向链表尾指针地址
 * @param data 需要插入的元素的值
 * @return 成功返回TRUE 失败返回FALSE
 * */
int ascending_insert(DuLinkList head, DuLNode **pTail, ElemType data)
{
    if (NULL == head)
    {
        printf("[%s %d] head point is NULL\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    //创建一个新的结点
    DuLNode *p = (DuLNode *)malloc(sizeof(DuLNode));
    p->pre = NULL;
    p->next = NULL;
    p->data = data;
​
    DuLNode *t = head->next;
    //判断是否为空
    if (NULL == head->next)
    {
        head->next = p;
        p->pre = head;
        *pTail = p;
        return TRUE;
    }
​
    while (t != NULL)
    {
        if (t->data <= data)
        {
            //继续往后遍历
            t = t->next;
            continue;
        }
​
        p->next = t;
        p->pre = t->pre;
        t->pre->next = p;
        t->pre = p;
        return TRUE;
    }
    //如果链表遍历完毕,说明需要插入的结点比链表上的所有结点都要大应该插入到链表的末尾
    (*pTail)->next = p;
    p->pre = *pTail;
    *pTail = p;
​
    /*
     * 假如没有尾指针,遍历链表的时候,当遍历到链表的最后一个结点的时候就要停止遍历
     * */
    /*
    while (t->next != NULL)
    {
        if (t->data <= data)
        {
            //继续往后遍历
            t = t->next;
            continue;
        }
​
        p->next = t;
        p->pre = t->pre;
        t->pre->next = p;
        t->pre = p;
        return TRUE;
    }
​
    if (t->data <= data){
        p->next = t;
        p->pre = t->pre;
        t->pre->next = p;
        t->pre = p;
    }
    else
    {
        t->next = p;
        p->pre = t;
    }
     */
    return TRUE;
}

10、删除双向链表上指定位置的结点

image.png

/*
 * @brief 删除指定位置的元素
 * @param head 双向链表头指针
 * @param pTail 双向链表尾指针地址
 * @param index 需要删除的元素的位置
 * @return 成功返回TRUE 失败返回FALSE
 * */
int delete_by_index(DuLinkList head, DuLNode **pTail, uint index)
{
    if (NULL == head)
    {
        printf("[%s %d] head point is NULL\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    if (0 == index)
    {
        printf("[%s %d] index must > 0\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    int i = 1;
    DuLNode *t = head->next;
    while (i < index && t != NULL)
    {
        i++;
        t = t->next;
    }
​
    //如果链表遍历完了
    if (NULL == t)
    {
        printf("[%s %d] index out of range ...\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    //如果要删除的结点恰好是尾结点
    if (t == *pTail)  //if (t->next == NULL)
    {
        *pTail = t->pre;
        (*pTail)->next = NULL;
        free(t);
        return TRUE;
    }
​
    //如果是中间结点
    t->pre->next = t->next;
    t->next->pre = t->pre;
    free(t);
    return TRUE;
}
​
int print_stack(SqStack *s)
{
    if (NULL == s)
    {
        printf("[%s %d] stack pointer is NULL ...\n");
        return FALSE;
    }
​
    ElemType *t = s->top;
    t--;
    while (t != s->base)
    {
        printf("%d ", *t);
        t--;
    }
    printf("%d \n", *t);
    return TRUE;
}

11、删除链表上指定的元素

/*
 * @brief 删除指定位置的元素
 * @param head 双向链表头指针
 * @param pTail 双向链表尾指针地址
 * @param data 需要删除的元素的值
 * @return 成功返回TRUE 失败返回FALSE
 * */
int delete_by_value(DuLinkList head, DuLNode **pTail, ElemType data)
{
    if (NULL == head)
    {
        printf("[%s %d] head point is NULL\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    DuLNode *t = head->next;
    //遍历整个链表
    while (t != NULL)
    {
        if (t->data != data)
        {
            t = t->next;
            continue;
        }
​
        //判断是否需要删除的结点恰好是尾结点
        if (t->next == NULL)
        {
            *pTail = t->pre;
            (*pTail)->next = NULL;
            free(t);
            return TRUE;
        }
​
        //如果是中间结点
        //先保存t结点的直接后继
        DuLNode *bak = t->next;
        t->pre->next = t->next;
        t->next->pre = t->pre;
        free(t);
        t = bak;
    }
​
    return TRUE;
}

12、销毁双向链表

/*
 * @brief 销毁链表
 * @param head 双向链表头指针
 * @param pTail 双向链表尾指针地址
 * @return 成功返回TRUE 失败返回FALSE
 */
int list_destroy(DuLinkList head, DuLNode **pTail)
{
    if (NULL == head)
    {
        printf("[%s %d] head point is NULL\n", __FUNCTION__ , __LINE__);
        return FALSE;
    }
​
    DuLNode *t = head->next;
    while (t->next != NULL)
    {
        //头结点的next指向t的后继结点
        head->next = t->next;
​
        //t的后继结点的pre指向头结点
        t->next->pre = head;
        free(t);
        t = head->next;
    }
​
    //剩下最后一个尾结点
    head->next = NULL;
    free(t);
    free(head);
    *pTail = NULL;
​
    return TRUE;
}
​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值