[数据结构] 双向带头链表的学习

一.带头,双向

1.带头可能对初学者来说是一种优势,因为有了头(哨兵位),不需要运用二级指针,因为第一的位置已经确定,(二级指针用在不带头的修改头的值), 相对来说可能更加好理解,但是带头,这个头哨兵位存储的数据却没有很大的意义,实践意义并不大.

2.双向的链表,有一个好处,解决了单链表不能够找到前一个的问题,链表之间形成了循环,数据的修改更加便捷,当然相对而言也是更加复杂的.

二.带头双向链表的实现

头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
​
​
// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
​
typedef struct ListNode
{
    LTDataType data;
    struct ListNode* next;
    struct ListNode* prev;
}ListNode;
​
​
// 创建返回链表的头结点.
ListNode* ListInitate();
​
// 双向链表销毁
void ListDestory(ListNode* pHead);
​
// 双向链表打印
void ListPrint(ListNode* pHead);
​
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
​
// 双向链表尾删
void ListPopBack(ListNode* pHead);
​
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
​
// 双向链表头删
void ListPopFront(ListNode* pHead);
​
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
​
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
​
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
主体部分的实现(realize.c)
#include"twohead.h"
​
//创建一个节点
ListNode* CreateNode(LTDataType x)
{
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    if (newnode == NULL)
    {
        printf("malloc failed");
        exit(-1);
    }
​
    newnode->data = x;
    newnode->next = NULL;
    newnode->prev = NULL;
    
    return newnode;
​
}
​
//链表的初始化
ListNode* ListInitate()
{
    ListNode* phead = CreateNode(-1);
    phead->next = phead;
    phead->prev = phead;
​
    return phead;
​
}
​
//链表的打印
void ListPrint(ListNode* pHead)
{
    if (pHead == NULL)
        return;
    printf("哨兵位<=>");
​
    ListNode* cur = pHead->next;
    while (cur != pHead)
    {
        printf("%d<=>", cur->data);
        cur = cur->next;
    }
​
}
​
//链表的销毁
void ListDestory(ListNode* pHead)
{
    free(pHead);
    pHead = NULL;
}
​
//链表的头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
    if (pHead == NULL)
        return;
    ListNode* cur = CreateNode(x);
    cur->next = pHead->next;
    pHead->next = cur;
    cur->prev = cur->next->prev;
    cur->next->prev = cur;
​
}
​
//链表的头删
void ListPopFront(ListNode* pHead)
{
    if (pHead == NULL)
        return;
    if (pHead->next == pHead)
        return;
​
    pHead->next = pHead->next->next;
    pHead->next->prev->prev = pHead;
​
}
​
//链表的尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
    if (pHead == NULL)
        return;
    ListNode* cur = CreateNode(x);
    
​
    pHead->prev->next = cur;
    cur->prev = pHead->prev;
    cur->next = pHead;
    pHead->prev = cur;
​
}
​
//链表的尾删
void ListPopBack(ListNode* pHead)
{
    if (pHead == NULL)
        return;
​
    if (pHead->next == pHead)
        return;
    
    pHead->prev->prev->next = pHead;
    pHead->prev = pHead->prev->prev;
​
}
​
//链表的查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
    if (pHead == NULL)
        return NULL;
    if (pHead->next == pHead)
        return NULL;
    ListNode* cur = pHead->next;
    while (cur!=pHead)
    {
        if (cur->data == x)
            return cur;
        cur = cur->next;
    }
​
    return NULL;
​
}
​
//链表pos位置之前的插入
void ListInsert(ListNode* pos, LTDataType x)
{
    if (pos == NULL)
        return;
    ListNode* cur = CreateNode(x);
    pos->prev->next = cur;
    cur->next = pos;
    cur->prev = pos->prev->next;
    pos->prev = cur;
}
​
//链表pos位置的删除
void ListErase(ListNode* pos)
{
    if (pos == NULL)
        return;
​
    pos->prev->next = pos->next;
    pos->next->prev = pos->prev;
​
}
测试样例的是实现
#include"twohead.h"
​
void test1()
{
    ListNode* head = ListInitate();
    ListPushFront(head, 1);
    ListPushFront(head, 2);
    ListPushFront(head, 3);
    ListPushFront(head, 4);
    ListPushFront(head, 5);
    ListPushFront(head, 6);
    ListPrint(head);
​
    ListDestory(head);
​
}
​
void test2()
{
    ListNode* head = ListInitate();
    ListPushFront(head, 1);
    ListPushFront(head, 2);
    ListPushFront(head, 3);
    ListPushFront(head, 4);
    ListPushFront(head, 5);
    ListPushFront(head, 6);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
    ListPopFront(head);
​
    ListPrint(head);
    
    ListDestory(head);
​
}
​
void test3()
{
    ListNode* head = ListInitate();
    ListPushBack(head, 1);
    ListPushBack(head, 2);
    ListPushBack(head, 3);
    ListPushBack(head, 4);
    ListPushBack(head, 5);
    ListPushBack(head, 6);
​
​
​
    ListPrint(head);
    ListDestory(head);
​
}
​
void test4()
{
    ListNode* head = ListInitate();
    ListPushBack(head, 1);
    ListPushBack(head, 2);
    ListPushBack(head, 3);
    ListPushBack(head, 4);
    ListPushBack(head, 5);
    ListPushBack(head, 6);
     ListPopBack(head);
     ListPopBack(head);
     ListPopBack(head);
     ListPopBack(head);
​
​
​
​
    ListPrint(head);
    ListDestory(head);
​
}
​
void test5()
{
    ListNode* head = ListInitate();
    ListPushBack(head, 1);
    ListPushBack(head, 2);
    ListPushBack(head, 3);
    ListPushBack(head, 4);
    ListPushBack(head, 5);
    ListPushBack(head, 6);
    ListPrint(head);
    printf("\n");
​
    ListNode*cur= ListFind(head, 102);
    printf("%p", cur);
    ListDestory(head);
​
}
​
void test6()
{
    ListNode* head = ListInitate();
    ListPushBack(head, 1);
    ListPushBack(head, 2);
    ListPushBack(head, 3);
    ListPushBack(head, 4);
    ListPushBack(head, 5);
    ListPushBack(head, 6);
    ListPrint(head);
    printf("\n");
​
    ListNode* cur = ListFind(head, 4);
    ListInsert(cur, 100);
    ListPrint(head);
    ListDestory(head);
​
}
​
void test7()
{
    ListNode* head = ListInitate();
    ListPushBack(head, 1);
    ListPushBack(head, 2);
    ListPushBack(head, 3);
    ListPushBack(head, 4);
    ListPushBack(head, 5);
    ListPushBack(head, 6);
    ListPrint(head);
    printf("\n");
​
    ListNode* cur = ListFind(head, 4);
    ListErase(cur);
    ListPrint(head);
    ListDestory(head);
​
}
​
int main()
{
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    //test6();
    //test7();
​
    return 0;
​
}

到此为止链表顺序表的所有内容讲解均完成.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值