[Estrutura de dados] Implementação de uma lista encadeada circular bidirecional (linguagem c)

Prefácio - as vantagens da lista duplamente encadeada

Lista vinculada circular bidirecional principal : a estrutura mais complexa , geralmente usada para armazenar dados separadamente.

A estrutura de dados de lista encadeada usada na prática é uma lista encadeada circular bidirecional com o lead.

Além disso, embora essa estrutura seja complexa , depois de usar o código para implementar, você descobrirá que a estrutura trará

As vantagens são muitas, mas a implementação é simples e saberemos quando implementarmos o código posteriormente.

1. Diagrama para assumir a liderança na estrutura da lista duplamente encadeada

Para uma lista encadeada individualmente, cada nó consiste em um dado e um ponteiro, e apenas o ponteiro precisa registrar o endereço do próximo nó.

Cada nó da lista duplamente encadeada é composto por dois ponteiros e um dado , um dos quais é usado para armazenar o endereço do nó anterior , e o outro ponteiro é usado para armazenar o endereço do próximo nó , realizando assim o lista de links bidirecionais. O diagrama esquemático da lista duplamente encadeada é o seguinte:

Entre eles, o ponteiro anterior é usado para salvar o endereço do nó anterior, o próximo ponteiro é usado para salvar o endereço do próximo nó e os dados são usados ​​para salvar os dados.

(1) Assuma a liderança na interface da lista encadeada circular bidirecional

2. Etapas para realizar a lista encadeada

  1. criar e inicializar

Primeiro, você precisa definir uma estrutura e, em seguida, solicitar espaço no heap como um nó principal (comumente conhecido como nó sentinela) e, em seguida, conectá-los de ponta a ponta. Como mostrado abaixo:

definir uma estrutura

Alocar espaço para a estrutura

Quando você solicitar espaço pela primeira vez, defina esses dois ponteiros como vazios (para evitar ponteiros selvagens) e, em seguida, atribua um valor aos dados

Em seguida, retorne o endereço do novo nó solicitado

inicialização

Deixe o nódulo da cabeça (nódulo sentinela) apontar para si mesmo para julgamento subsequente

  1. Plugue da cauda e exclusão da cauda e interface de impressão

(1) Inserção de cauda , da lista vinculada circular (o diagrama no início), podemos saber que o ponteiro anterior do nó principal aponta para a cauda da lista vinculada, deixe o ponteiro da cauda apontar para a cauda primeiro,

Em seguida, deixe o anterior do nó principal apontar para o novo nó (neste momento, o novo nó é o nó final),

Em seguida, deixe o próximo ponteiro do nó de cauda original apontar para newnode,

再让newnode的next指针指向头节点(phead)实现循环,

最后让newnode的prev指针指向tail(原来的尾节点)即可

2)尾删前需要判断一下链表是否为空,因此创建一个判断链表是否为空的接口

(3)尾删,用一个指针记录一下尾节点的地址,

然后让尾节点的上一个节点指向头节点,

再让头节点的prev指针指向此时尾节点的上一个节点,

最后把为节点释放掉就好了,

这里我没有让tail指针置空,是因为tail是局部变量,该函数一调用完,该函数的栈帧就会立马

被销毁(tail也被销毁了),所以我觉得没必要(不会发生野指针问题),当然想置空也是可以的

(4)打印接口

这里只需要注意当tail等于头指针时结束遍历即可,因为该链表为循环链表如果没有这个条件将会发生死循环,最后程序会崩掉

3.头插和头删

头插,该链表的头插和链表的头插有点区别,就是需要把新节点插到头节点的后面

让新节点的next指针指向原来的头节点的下一个节点,

让新节点的prev节点指向头节点,

然后让头节点的下一个节点的prev指针指向新节点,

最后让头节点的next指针指向新节点

头删删除链表中的数据肯定先要判断链表是否为空,所以进行了一下断言

定义一个指针first用来保存被删除的节点,

然后让头节点指向被删除节点(first)的下一个节点,

然后再让first指针的下一个节点的prev指针指向头节点

最后把first指向的节点释放掉就好了

  1. 任意元素前的插入和任意元素的删除

任意元素前的插入

让新节点的next指针指向pos节点

然后让新节点的prev指向pos节点的上一个节点

再让新节点的上一个节点(原来pos节点的上一个节点)的next指向新节点

最后让pos节点的prev指针指向新节点

任意元素的删除

先让pos节点的上一个节点的next指针指向pos节点的下一个节点,

然后再让pos节点的下一个节点的prev指针指向pos节点的上一个节点

最后释放掉pos节点,把pos节点置空即可

  1. 元素的查找

查找要找的元素,如果找到就返回该节点,如果找不到就返回NULL

  1. 链表的销毁

把申请的链表给删掉,不过多阐述了

三.一些小技巧

1.任意元素前插入(头插)

当我们在需要在较短的时间内写出一个双向循环链表的时候

可以只写 任意元素前的插入、和任意元素的删除即可

因为当给任意元素前的插入接口传头节点的next指针指向的地址时,相当于头插(如下图)

2.任意元素前插入(尾插)

当给任意元素前的插入接口传plist(头节点)的地址时,相当于尾插(如下图)

因为链表是从plist(头节点)的下一个节点开始遍历,

最后才到头节点

3.任意元素的删除(头删)

当给该接口传头节点的next指针指向的地址时,此时该接口相当于头删,如下图:

4.任意元素的删除(尾删)

给该接口传头节点的prev指针指向的地址时,此时该接口相当尾删,如下图:

今日份享就到这里了,路过的小伙们给个关注和小赞吧,如果有错误也请指出来,让我们共同进步吧(886)!!!

Acho que você gosta

Origin blog.csdn.net/m0_72532428/article/details/129477992
Recomendado
Clasificación