数据结构与算法 — 双链表

1、双链表的结构

在这里插入图片描述
从图结构可以看出,双链表具有一个指向前驱结点的指针和一个指向后继结点的指针,所以,双链表中,结点是这样定义的:

typedef int Elem;

typedef struct DualNode {
    Elem elem;
    struct DualNode *prev;    //前驱结点
    struct DualNode *next;     //后继结点
} DualNode;

typedef struct {
    DualNode dummy;
    int length;
}List;

一个含有假结点的完整循环双链表:
在这里插入图片描述

空表:
在这里插入图片描述

2、创建一个新结点

生成一个新的结点,结点的值通过参数传入:

DualNode *nodeNew(Elem elem)  //生成一个结点
{
    DaulNode *node = malloc(sizeof(DaulNode));
    node -> next = NULL:
    node -> prev = NULL;
    node -> elem = elem;
    return node;
}

释放结点:

void nodeDelete(DaulNode *node)
{
    free(node);
}

3 、插入结点

有一个新的结点s,要插入到p结点的前面,一定要按照下面几步顺序来完成:
在这里插入图片描述

void nodeLink(DaulNode *prev,DaulNode *s,DaulNode *next)
{
    s -> next = next;
    s -> prev = p ->prev;
    prev -> next = s;
    next -> prev = s;
}

第四部不可提前执行;

4、删除结点

删除结点更为简单:
在这里插入图片描述

void nodeUnlink(Daulnode *p)
{
    p -> prev ->next = p ->next;
    p -> next -> prev= p -> prior;
    free(p);
}

5、创建双链表

void listInit(List *list)
{
    DaulNode *dummy = &list -> dummy;
  
    dummy -> next = dummy;
    dummy -> prev = dummy;
    dummy -> length = 0;
}

dummy是一个假结点,也就是头结点,他的数据段用来存放链表的长度;

6、销毁双链表

销毁结点实则是把链表转化为空表的一个过程,通过一 一删除假结点的后继(头结点)来完成链表的销毁:

void listDestroy(List *list)
{
    DaulNode *dummy = &list -> dummy; 
    
    while(dummy -> next != dummy)
    {
        DaulNode *node = dummy -> next;
        nodeUnlink(node);
        nodeDelete(node);
        list -> length--;
    }
}

7、获取头结点结点和尾结点

头结点是指第一个真实结点,而假结点指向头结点

DaulNode *GetHeadNode(List *list)
{
    asser(list -> length > 0);
    return list -> dummy.next;
}

DaulNode *GetTailNode(List *list)
{
    asser(list -> length > 0);
    return list -> dummy.prev;
}

8、链表长度

假结点还有一个成员length

int listLength(List *list)
{
    return list -> length;
}

判断链表是空同样用length即可;

9、获取指定位置的结点

DaulNode *GetNode(List *list,int index)
{
    assert(index >= 0 && index <= list -> length);
    int i;
    DaulNode *node;

    node = list -> dummy.next;  //指向链表的头结点
    for(i = 0; i < index; i++)
        node = node -> next;

    assert(i == index);
    return node;
}

10、设置指定位置的元素

先获取结点,在设置元素值;

void PutElem(List *list,int index,Elem elem)
{
    asser(index >= 0 && index < list -> length);
    DaulNode *node = GetNode(list,index);
    node -> elem = elem;
}

11、遍历双链表

void listVisit(List *list)
{
    DaulNode *node;
    DaulNode *dummy = &list -> dummy;

    for(node = dummy -> next; node != dummy;node = node -> next){
        printf(" %d <-->",node -> elem);
    }
    printf("\n");
}

12、已知数值找位置

int LocateElem(List *list,Elem targetElem)
{
    DaulNode *node;
    DaulNode *dummy = &list -> dummy;
    int index = 0; 
    for(node = dummy -> next; node != dummy; node = node -> next){
        if(node -> elem == elem)
            return index;
        index++;
    }

}

13、在指定位置插入元素

void InsertElem(List *list,int index,Elem elem)
{
    assert(index >= 0 && index <= list -> length);
    DaulNode *node = nodeNew(elem);
    DaulNode *next = GetNode(list,index);
    DaulNode *prev = next -> prev;
    nodeLink(prev,node,next);
    list -> length++:
}

14、尾部添加元素

void AppendElem(List *list,Elem elem)
{
    int length = listLength(list);
    InsertElem(list,length,elem);
}

15、删除指定位置的结点

void DeleteElem(List *list,int index)
{
    assert(index >= 0 && index <= list -> length);
    DaulNode *node = GetNode(list,index);
    nodeUnlink(node);
    nodeDelete(node);
    list -> length--;

这些就是关于双链表的基本操作了。

猜你喜欢

转载自blog.csdn.net/weixin_45121946/article/details/106489293