重学数据结构(二)双链表

版权声明:@Keanu https://blog.csdn.net/weixin_41174072/article/details/83213483

这次是系列二,双链表,具体的说明就不太详细说了,注释都加到Code中去了,很详细,特此记录~

还是先简单说一下双链表:

以下是维基百科中对双链表的定义:

双向链表,又称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

再看直观图:

双链表

循环双链表

其实循环双链表只是将一个链变成了一个环,他们都可以从任意一个位置开始,访问链上的任意一个元素,循环链表的尾节点的next指针指向了头结点,而头节点的prior指针则是指向了尾节点.

接下来就是双链表的一些基本功能,而循环列表就需要进一步的拓展了,这里不再赘述:

首先是DLinkList.h:
#include <stdio.h>
#include <malloc.h>

#ifndef DLNODE_DLINKLIST_H
#define DLNODE_DLINKLIST_H
#define TRUE 1
#define ERROR 0

//双链表
typedef struct DLNode {
    int data;
    struct DLNode *prior;
    struct DLNode *next;
} DLinkList;

/**
 * 头插法建立双链表
 * @param L 双链表
 * @param a 链表元素
 * @param n 链表长度
 * @return 返回的是生成的链表的首节点的地址
 */
DLinkList * CreateListByHead(DLinkList *L, int a[], int n) {
    DLinkList *s;
    L->prior = L->next = NULL;
    for (int i = 0; i < n; ++i) {
        s = (DLinkList *) malloc(sizeof(DLinkList));
        s->data = a[i];
        s->next = L->next;
        if (L->next != NULL)
            L->next->prior = s;
        L->next = s;
        s->prior = L;
    }
    return L;
}

/**
 * 尾插法建立双链表
 * @param L 双链表
 * @param a 链表元素
 * @param n 链表长度
 * @return 返回的是生成的链表的首节点的地址
 */
DLinkList * CreateListByRoil(DLinkList *L, int a[], int n) {
    DLinkList *r = L, *s; //r指针用来指向L的尾节点,s 是每次产生的新的节点
    for (int i = 0; i < n; ++i) {
        s = (DLinkList *) malloc(sizeof(DLinkList));
        s->data = a[i];
        r->next = s;
        s->prior = r;
        r = s;//r始终指向链表的尾节点
    }
    r->next = NULL;
    return L;
}

/**
 * 在双链表某逻辑位置上插入值为e的元素
 * @param L 传入的双链表
 * @param i 逻辑位置
 * @param e 插入的元素
 * @return 插入成功返回TRUE(1),失败返回ERROR(0)
 */
int ListInsert(DLinkList *L, int i, int e) {
    DLinkList *r = L, *s;
    int j = 0;
    while (r != NULL && j < i - 1) {//找到第i-1个位置
        j++;
        r = r->next;
    }
    if (r == NULL)
        return ERROR;
    else {
        s = (DLinkList *) malloc(sizeof(DLinkList));
        s->data = e;
        s->next = r->next;
        //可能在最后一个节点之后插入,此时最后一个节点的next为NULL,不包含指针
        if (r->next != NULL)
            r->next->prior = s;
        r->next = s;
        s->prior = r;
        return TRUE;
    }
}

/**
 * 删除双链表上逻辑位置的元素
 * @param L 双链表
 * @param i 逻辑位置
 * @return 成功返回TRUE(1),失败返回ERROR(0)
 */
int ListDelete(DLinkList *L, int i) {
    DLinkList *p = L, *q;
    int j = 0;
    //首先找到逻辑位置第i-1个元素,防止指针断链
    //跟下标没有关系,因为j<i最后出来的是移动次数
    while (p != NULL && j < i - 1) {
        j++;
        p = p->next;
    }
    if (p == NULL)
        return ERROR;
    else {
        q = p->next;
        //删除位置为空
        if (q == NULL) {
            return ERROR;
        }
        p->next = q->next;
        //这里其实要分成两种情况,但是最后提取了一下代码
        //可能删除的是最后一个节点
        if (q->next != NULL)
            q->next->prior = p;
        free(q);
        return TRUE;
    }
}

/**
 * 输出双链表
 */
void OutputLink(DLinkList *L){
    //输出前i-1个元素
    while (L->next != NULL){
        printf("%d<=>",L->data);
        L = L->next;
    }
    printf("%d",L->data);
}

#endif //DLNODE_DLINKLIST_H

main函数:
#include <stdio.h>
#include "DLinkList.h"
#define MAX_SIZE 5

int main() {

    DLinkList *L = (DLinkList *) malloc(sizeof(DLinkList));
    int a[MAX_SIZE];
    for (int i = 0; i < MAX_SIZE; ++i) {
        a[i] = i+1;
    }
    //头插法创建双链表
    printf("\n头插法建立的双链表为:             ");
    OutputLink(CreateListByHead(L, a, MAX_SIZE));

    //尾插法创建双链表
    printf("\n尾插法建立的双链表为:             ");
    OutputLink(CreateListByRoil(L, a, MAX_SIZE));

    //在特定位置插入(注意,此时的L为尾插法建立的链表)
    int k = ListInsert(L, 6, 9);
    if (k == 0)
        printf("\nERROR!");
    else
        printf("\n在第六个位置插入后的双链表为:     "); OutputLink(L);

    //删除特定位置元素(注意,此时的L为尾插法建立的链表)
    int z = ListDelete(L, 6);
    if (z == 0)
        printf("\nERROR!");
    else
        printf("\n删除第六个位置的元素后的双链表为: ");OutputLink(L);

    return 0;
}
最后的结果图:

结果图

猜你喜欢

转载自blog.csdn.net/weixin_41174072/article/details/83213483