雙鏈表的一些簡單操作

.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");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章