双链表的一些简单操作

.h文件

#pragma once
typedef char DLinkType;

typedef struct DLinkNode
{
  DLinkType data;
  struct DLinkNode* prev;
  struct DLinkNode* next;
}DLinkNode;

void DLinkListInit(DLinkNode** phead) ;//初始化

void DLinkListPushBack(DLinkNode* head,DLinkType value);//尾插
void DLinkListPopBack(DLinkNode* head);//尾删
void DLinkListPushFront(DLinkNode* head,DLinkType value);//头插
void DLinkListPopFront(DLinkNode* head);//头删
void DLinkListInsert(DLinkNode* head,DLinkNode* pos,DLinkType value);//在pos前插入;
void DLinkListInsertAfter(DLinkNode* head,DLinkNode* pos,DLinkType value);//在pos后插
DLinkNode* DLinkListFind(DLinkNode* head,DLinkType to_find);//给定一个值查找位置
void DLinkListErase(DLinkNode* head,DLinkNode* to_delete);//删除某个位置上的元素
void DLinkListRemove(DLinkNode* head,DLinkType to_delete_value);//删除第一个值为to_delete_value的元素
void DLinkListRemoveAll(DLinkNode* head,DLinkType to_delete_value);//删除所有值为to_delete_value的元素
void DLinkListDestroy(DLinkNode** phead);//销毁整个链表
size_t DLinkListSize(DLinkNode* head);//求链表元素个数
int DLinkListEmpty(DLinkNode* head);//判断链表是否为空

.c文件

#include"DLinkList.h"
#include <stdio.h>
#include<stdlib.h>
#include<stddef.h>

创建和销毁节点

DLinkNode* CreateDLinkNode(DLinkType value)
{
    DLinkNode* new_node = (DLinkNode*)malloc(sizeof(DLinkNode));
    new_node->data = value;
    new_node->prev = new_node;
    new_node->next = new_node;
    return new_node;
}
void DestroyDLinkNode(DLinkNode* pos)
{
    free(pos);
}

打印链表

void DLinkListPrintChar(DLinkNode* head,const char* msg)
{
    printf("[%s]\n",msg);
    DLinkNode* cur = head->next;
    //先正向打印
    for(;cur != head;cur = cur->next )
    {
        printf("[%c|%p]",cur->data,cur);
    }
    printf("\n");
    //再反向打印
    for(cur = head->prev;cur != head;cur = cur->prev )
    {
        printf("[%c|%p]",cur->data,cur);
    }
    printf("\n");
    return;
}

1.链表的初始化与测试函数

void DLinkListInit(DLinkNode** head)
{
    if(head == NULL)
    {
     //非法输入
     return;
    }
    *head = CreateDLinkNode(0);
}
void TestInit()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    printf("head expected not NULL, actual %p\n",head);
    printf("data expect 0,actual %d\n",(int)head->data);
}

2.尾插一个元素

void DLinkListPushBack(DLinkNode* head,DLinkType value)
{
    if(head == NULL)
    {
        //非法输入
        return;
    }
    DLinkNode* tail = head->prev;
    //先创建一个值为value的新节点
    DLinkNode* new_node = CreateDLinkNode(value);
    //head  vs  new_node
    //设置新节点的next值和head的prev值
    new_node->next = head;
    head->prev =  new_node;
    //tail  vs  new_node
    //设置最初的尾节点的next值为新节点
    //新节点的prev为最初的尾节点
    tail->next = new_node;
    new_node->prev = tail;
    return;
}
void TestPushBack()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrintChar(head,"尾插四个元素");
}

3.尾删一个元素

void DLinkListPopBack(DLinkNode* head)
{
    if(head == NULL)
    {
        //非法输入
        return;
    }
    if(head->next == head)
    {
        //空链表
        return;
    }
    DLinkNode* to_delete = head->prev;
    DLinkNode* prev = to_delete->prev;
    //只需要将倒数第二个元素的next和head的prev进行修改
    prev->next = head;
    head->prev = prev;
    DestroyDLinkNode(to_delete);
    return;
}
void TestPopBack()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrintChar(head,"尾插四个元素");
    DLinkListPopBack(head);
    DLinkListPopBack(head);
    DLinkListPrintChar(head,"尾删两个元素");
    DLinkListPopBack(head);
    DLinkListPopBack(head);
    DLinkListPrintChar(head,"再尾删两个元素");
    DLinkListPopBack(head);
    DLinkListPrintChar(head,"尝试对空链表进行删除");
}

4.头插一个元素

void DLinkListPushFront(DLinkNode* head,DLinkType value)
{
    if(head == NULL)
    {
        //非法输入
        return;
    }
    DLinkNode* new_node = CreateDLinkNode(value);
    DLinkNode* next_node = head->next;
    //head  vs  new_node
    //将新节点插入到head后
    //修改head的next
    //设置新节点的prev为head
    head->next = new_node;
    new_node->prev = head;
    //new_node  vs  next_node
    //设置新节点的next值为原head后的节点
    //修改原head后的节点的prev为新节点
    new_node->next = next_node;
    next_node->prev = new_node;
    return;
}
void TestPushFront()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushFront(head,'a');
    DLinkListPushFront(head,'b');
    DLinkListPushFront(head,'c');
    DLinkListPushFront(head,'d');
    DLinkListPrintChar(head,"头插四个元素");
}

5.头删一个元素

void DLinkListPopFront(DLinkNode* head)
{
    if(head == NULL)
    {
        //非法输入
        return;
    }
    if(head->next == head)
    {
        //空链表
        return;
    }
    DLinkNode* to_delete = head->next;
    DLinkNode* next_node = to_delete->next;
    //修改head的next值为原第二个元素
    head->next = next_node;
    //修改原第二个元素的prev为head
    next_node->prev = head;
    DestroyDLinkNode(to_delete);
    return;
}
void TestPopFront()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushFront(head,'a');
    DLinkListPushFront(head,'b');
    DLinkListPushFront(head,'c');
    DLinkListPushFront(head,'d');
    DLinkListPrintChar(head,"头插四个元素");
    DLinkListPopFront(head);
    DLinkListPopFront(head);
    DLinkListPrintChar(head,"头删两个元素");
    DLinkListPopFront(head);
    DLinkListPopFront(head);
    DLinkListPrintChar(head,"再头删两个元素");
    DLinkListPopFront(head);
    DLinkListPrintChar(head,"尝试对空链表进行头删");
}

6.在pos前插入一个元素

void DLinkListInsert(DLinkNode* head,DLinkNode* pos,DLinkType value)//在pos前插入
{
    if(head == NULL || pos == NULL)
    {
        //非法输入
        return;
    }
    DLinkNode* new_node = CreateDLinkNode(value);
    DLinkNode* prev = pos->prev;
    //pos  vs  new_node
    //修改pos的prev为新节点
    //设置新节点的next值为pos
    pos->prev = new_node;
    new_node->next = pos;
    //prev  vs  new_node
    //修改原pos前一个节点的next值为新节点
    //设置新节点的prev为原pos的前一个节点
    prev->next = new_node;
    new_node->prev = prev;
    return;
}
void TestInsert()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListInsert(head,head->next->next,'x');
    DLinkListPrintChar(head,"在 b 元素之前插入x元素");
}

7.在pos后插入一个元素

void DLinkListInsertAfter(DLinkNode* head,DLinkNode* pos,DLinkType value)
{
    if(head == NULL || pos == NULL)
    {
        //非法输入
        return;
    }
    DLinkNode* new_node = CreateDLinkNode(value);
    DLinkNode* next_node = pos->next;
    //new_node vs pos
    //修改pos的next值为新节点
    //设置新节点的prev为pos
    pos->next = new_node;
    new_node->prev = pos;
    //next_node  vs  next_node
    //修改原pos后节点的prev值
    //设置新节点的next值为原pos后的节点
    next_node->prev = new_node;
    new_node->next = next_node;
    return;
}
void TestInsertAfter()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListInsertAfter(head,head->next->next,'x');
    DLinkListPrintChar(head,"在 b 元素之后插入x元素");
}

8.给定一个值查找位置

DLinkNode* DLinkListFind(DLinkNode* head,DLinkType to_find)
{
    if(head == NULL)
    {
        //非法输入
        return NULL;
    }
    DLinkNode* cur = head->next;
    for(;cur != head;cur = cur->next)
    {
        if(cur->data == to_find)//如果cur节点对应的值和我们要找的值相等,则返回该节点
        {
            return cur;
        }
    }
    return NULL;
}
void TestFind()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkNode* pos1 = DLinkListFind(head,'b');
    printf("pos1 : expected %p ,actual %p \n",head->next->next,pos1);
    DLinkNode* pos2 = DLinkListFind(head,'x');
    printf("pos2 : expected NULL, actual %p \n",pos2);
}

9.删除某个位置上的元素

void DLinkListErase(DLinkNode* head,DLinkNode* to_delete)
{
    if(head == NULL || to_delete == NULL)
    {
        //非法输入
        return;
    }
    if(head == to_delete)
    {
        //非法输入,head指向的元素是不能被释放的,除非在销毁整个链表的时候
        return;
    }
    DLinkNode* prev_node = to_delete->prev;//找到要删除节点的前一个节点
    DLinkNode* next_node = to_delete->next;//找到要删除节点的后一个节点
    //修改前一个节点的next和后一个节点的prev
    prev_node->next = next_node;
    next_node->prev = prev_node;
    DestroyDLinkNode(to_delete);
    return;
}
void TestErase()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListErase(head,head->next->next);
    DLinkListPrintChar(head,"删除链表中的 b 元素");
}

10.删除第一个值为to_delete_value的元素

void DLinkListRemove(DLinkNode* head,DLinkType to_delete_value)
{
    if(head == NULL)
    {
        //非法输入
        return;
    }
    DLinkNode* cur = DLinkListFind(head,to_delete_value);
    if(cur == NULL)//如果没有找到值为to_delete_value的元素直接返回不需要再删除
    {
        //没有
        return;
    }
    DLinkListErase(head,cur);
}
void TestRemove()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListRemove(head,'b');
    DLinkListPrintChar(head,"删除链表中的第一个 b 元素");
}

11.删除所有值为to_delete_value的元素

void DLinkListRemoveAll(DLinkNode* head,DLinkType to_delete_value)
{
    if(head == NULL)
    {
        //非法输入
        return;
    }
    DLinkNode* cur = head->next;
    while(cur != head)
    {
       if(cur->data == to_delete_value)
       //如果cur指向的节点里的值和要删除元素的值相等,就删除该节点
       {
            DLinkListErase(head,cur);
       }
       cur = cur->next;
    }       
    return;
}
void TestRemoveAll()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'d');
    DLinkListPushBack(head,'b');
    DLinkListRemoveAll(head,'b');
    DLinkListPrintChar(head,"删除链表中所有的 b 元素");
}

12.销毁整个链表

void DLinkListDestroy(DLinkNode** phead)
{
    if(phead == NULL)
    {
        return;
    }
    DLinkNode* cur = (*phead)->next;
    while(cur != *phead)//先删除除了head的其他节点
    {
        DLinkNode* next = cur->next;
        DestroyDLinkNode(cur);
        cur = next;
    }
    DestroyDLinkNode(*phead);//销毁头节点
    *phead = NULL;//将头节点置空,若不置空就成了野指针
}
void TestDestroy()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListDestroy(&head);
}

13.求链表中的元素个数

size_t DLinkListSize(DLinkNode* head)
{
    if(head == NULL)
    {
        //非法输入
        return 0;
    }
    DLinkNode* cur = head->next;
    size_t i = 0;
    //cur从head的next开始走,走一步i++,直到最后一个元素
    for(;cur != head;cur = cur->next)
    {
        i++;
    }
    return i;
}
void TestSize()
{
    TEST_HEADER;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'d');
    size_t i = DLinkListSize(head);
    DLinkListPrintChar(head,"打印链表中的元素");
    printf("size is :%d\n",i);
}

14.判断链表是否为空,若为空返回1,不为空返回2

int DLinkListEmpty(DLinkNode* head)
{
    if(head == NULL)
    {
        //非法输入
        return 0;
    }
    if(head->next == head)//如果head的next还是head的话该链表就没有元素
    {
        return 1;
    }
    return 2;
}
void TestEmpty()
{
    TEST_HEADER;
    DLinkNode* head1;
    DLinkListInit(&head1);
    int a = DLinkListEmpty(head1);
    DLinkListPrintChar(head1,"打印链表中的元素");
    if(a == 1)
    {
        printf("该链表为空\n");
    }
    else
    {
        printf("该链表不为空\n");
    }

    DLinkNode* head2;
    DLinkListInit(&head2);
    DLinkListPushBack(head2,'a');
    DLinkListPushBack(head2,'b');
    DLinkListPushBack(head2,'a');
    DLinkListPushBack(head2,'c');
    int b = DLinkListEmpty(head2);
    DLinkListPrintChar(head2,"打印链表中的元素");
    if(b == 1)
    {
        printf("该链表为空\n");
    }
    else
    {
        printf("该链表不为空\n");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章