数据结构

数据结构(4)-线性表之双向链表

2020-04-07  本文已影响0人  xxxxxxxx_123

定义

在单向链表的元素中,添加一个指向前驱元素(也就是前一个元素)的指针域。元素中既有指向前驱元素的指针,又有指向后继元素的指针。这种形式的链表叫做双向链表。

其存储结构如下:

typedef int ElementType;

typedef struct DouNode{
    ElementType data;
    struct DouNode *next;
    struct DouNode *prior;
}DouNode;

typedef struct DouNode * linkList;

双向链表

初始化双向链表

TStatus InItDoubleLinkList(LinkList *dl) {
    (*dl) = (LinkList)malloc(sizeof(DouNode));
    if (*dl == NULL) {
        return T_ERROR;
    }
    (*dl)->data = -1;
    (*dl)->next = NULL;
    (*dl)->prior = NULL;
    return T_OK;
}
双向插入.png

插入双向链表的元素

双向链表由于存在两个指针域,所以插入的时候需要对其进行处理。

在第i个位置插入元素,大概步骤如下:

TStatus InsertElement(LinkList *dl, int i, ElementType e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    LinkList p = (*dl);
    int j = 1;
    while (p && j < i) {
        p = p->next;
        j += 1;
    }
    if (p == NULL || j > i) {
        return T_ERROR;
    }
    
    // 新插入的元素
    LinkList q = (LinkList)malloc(sizeof(DouNode));
    q->data = e;
    
    // q的指向
    q->next = p->next;
    q->prior = p;
    
    // q后继元素的指向
    if (p->next != NULL) {
        p->next->prior = q;
    }
    
    // p的指向
    p->next = q;
    
    return T_OK;
}

删除双向链表的元素

双向删除.png

删除第i个位置的元素,大概步骤如下:

TStatus DeleteElement(LinkList *dl, int i, ElementType *e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    LinkList p = (*dl);
    int j = 1;
    // 1234
    while (p && j < i) {
        p = p->next;
        j += 1;
    }
    if (p == NULL || j > i) {
        return T_ERROR;
    }
    
    LinkList delQ = p->next;
    *e = delQ->data;
    p->next = delQ->next;
    if (delQ->next != NULL) {
        delQ->next->prior = p;
    }
    
    free(delQ);
    
    return T_OK;
}

也可以通过数据来删除具有相同的数据的元素,此处我们只考虑链表中最多只有一个元素数据为传入的数据。

TStatus DeleteElementWithData(LinkList *dl, ElementType e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    LinkList p = (*dl);
    
    while (p != NULL) {
        if (p->data == e) {
            break;
        }
        p = p->next;
    }
    
    if (p == NULL) {
        return T_ERROR;
    }
    // 要删除的前一个元素
    LinkList preQ = p->prior;
    preQ->next = p->next;
    if (p->next != NULL) {
        p->next->prior = preQ;
    }
    free(p);
    
    return T_OK;
}

获取元素

获取双向链表第i个位置的元素。

TStatus GetElement(LinkList *dl, int i, ElementType *e) {
    if (*dl == NULL || i < 1) {
        return T_ERROR;
    }
    
    LinkList p = (*dl);
    int j = 1;
    
    while (p && j < i) {
        p = p->next;
        j += 1;
    }
    
    if (p->next == NULL && j > i) {
        return T_ERROR;
    }
    
    *e = p->next->data;
    
    return T_OK;
}

整表创建

采用尾插法整表创建双向链表:

TStatus createDoubleLinkList(LinkList *dl, int arr[], int size) {
    *dl = (LinkList)malloc(sizeof(DouNode));
    if (*dl == NULL) {
        return T_ERROR;
    }
    (*dl)->data = -1;
    (*dl)->prior = NULL;
    (*dl)->next = NULL;
    
    LinkList r = (*dl);
    LinkList p;
    for (int i = 0; i < size; i++) {
        int e = arr[i];
        p = (LinkList)malloc(sizeof(DouNode));
        if (p == NULL) {
            return T_ERROR;
        }
        p->data = e;
        p->prior = r;
        p->next = NULL;
        r->next = p;
        r = p;
    }
    
    return T_OK;
}

双向循环链表

双向循环链表的概念其实和单向循环链表类似,也是将链表中最后一个结点的next针由空指针改为指向头指针指向的元素,不同的是我们还需要将头指针指向的元素的前驱指针prior指向最后一个结点,这样链表就形成了一个环。

双向循环.png

初始化双向循环链表

初始化双向循环链表的时候,需要将自己的nextprior都指向自己。

TStatus InItDoubleLinkList(LinkList *dl) {
    (*dl) = (LinkList)malloc(sizeof(DouNode));
    if (*dl == NULL) {
        return T_ERROR;
    }
    (*dl)->data = -1;
    (*dl)->next = (*dl);
    (*dl)->prior = (*dl);
    return T_OK;
}

双向循环链表删除元素

TStatus DeleteElement(LinkList *dl, int i, ElementType *e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    
    LinkList p = (*dl);
    int j = 1;
    
    // 找到需要删除的位置的前一个位置
    while (p && j < i && p->next != (*dl)) {
        p = p->next;
        j += 1;
    }
    
    if (p->next == NULL || j > i) {
        return T_ERROR;
    }
    
    LinkList delQ = p->next;
    *e = delQ->data;
    delQ->prior = p;
    p->next = delQ->next;
    free(delQ);
    
    return T_OK;
}

可以看出来,双向循环链表和双向链表的操作类似,只是多了循环的相关处理。

线性表总结

  1. 线性表是零个或者多个具有相同类型的数据元素的有限序列。
  1. 线性表的存储结构:
上一篇下一篇

猜你喜欢

热点阅读