带头结点的链表:创建一个新结点表示空链表,该结点即为头结点,且头结点中的数据无任何意义
不带头结点的链表:用NULL表示空链表
头结点的好处:不用考虑头指针的指向问题,只要头指针初始化完成,就永远指向头结点,仅在要销毁整个链表时考虑
DLinklist.h
//带头结点、带环、双向链表
#pragma once
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#define SHOW_NAME printf("\n===================%s=================\n",__FUNCTION__);
typedef char DLinkType;
typedef struct DLinkNode
{
DLinkType data;
struct DLinkNode* prev;
struct DLinkNode* next;
}DLinkNode;
DLinkNode* CreateDLinkNode(DLinkType value);//创建一个新结点
void DLinklistInit(DLinkNode** phead);//初始化
void DLinklistPushBack(DLinkNode* head,DLinkType value);//尾插
void DestroyNode(DLinkNode* node);//销毁结点
void DLinklistPopBack(DLinkNode* head);//尾删
void DLinklistPushFront(DLinkNode* head,DLinkType value);//头插
void DLinklistPopFront(DLinkNode* head);//头插
DLinkNode* DLinklistFind(DLinkNode* head,DLinkType value);//查找值为value的结点,找到返回结点,找不到返回NULL
void DLinklistInsertBefore(DLinkNode* head,DLinkNode* pos,DLinkType value);//向pos位置前插入
void DLinklistInsertAfter(DLinkNode* head,DLinkNode* pos,DLinkType value);//向pos位置后插入
void DLinklistErase(DLinkNode* head,DLinkNode* pos);//删除pos位置结点
void DLinklistRemove(DLinkNode* head,DLinkType value);//删除值为value的结点
void DLinklistRemoveAll(DLinkNode* head,DLinkType value);//删除值为value的所有结点
void DLinklistDestroy(DLinkNode** phead);//销毁结点
DLinklist.c
#include "DLinklist.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 DLinklistInit(DLinkNode** phead)//初始化
{
if(phead == NULL)//非法操作
return;
*phead = CreateDLinkNode(0);//头结点中的数据无任何意义,任意置
}
void DLinklistPushBack(DLinkNode*head,DLinkType value)//尾插结点(修改四个指针)
{
if(head == NULL)//非法操作
return;
//不用考虑链表为空的情况,它可以合并到以下代码
DLinkNode* new_node = CreateDLinkNode(value);
DLinkNode* tail = head->prev;
head->prev = new_node;//head与new_node
new_node->next = head;
tail->next = new_node;//tail与new_node
new_node->prev = tail;
return;
}
void DestroyNode(DLinkNode* node)//销毁结点
{
free(node);
}
void DLinklistPopBack(DLinkNode* head)//尾删(修改两个指针)
{
if(head == NULL)//非法操作
return;
if(head->prev == head)//空链表
//if(head->next == head)
return;
DLinkNode* to_delete = head->prev;
DLinkNode* tail = to_delete->prev;
head->prev = tail;
tail->next = head;
DestroyNode(to_delete);
return;
}
void DLinklistPushFront(DLinkNode* head,DLinkType value)//头插(修改四个指针)
{
if(head == NULL)//非法操作
return;
DLinkNode* new_node = CreateDLinkNode(value);
DLinkNode* next_node = head->next;
head->next = new_node;//head与new_node
new_node->prev = head;
new_node->next = next_node;//next_node与new_node
next_node->prev = new_node;
return;
}
void DLinklistPopFront(DLinkNode* head)//头删(修改两个指针)
{
if(head == NULL)//非法操作
return;
if(head->prev == head)//空链表
return;
DLinkNode* to_delete = head->next;
DLinkNode* next_node = to_delete->next;
head->next = next_node;
next_node->prev = head;
DestroyNode(to_delete);
return;
}
void DLinklistPrint(DLinkNode* head,const char* msg)//打印链表
{
printf("[%s]\n",msg);
DLinkNode* cur = head->next;
for(; cur!=head; cur=cur->next)//正向打印,判断所有的next指针指向是否正确
{
printf("[%c|%p] ",cur->data,cur);
}
printf("\n");
for(cur=head->prev; cur!=head; cur=cur->prev)//逆向打印,判断所有的prev指向是否正确
{
printf("[%c|%p] ",cur->data,cur);
}
printf("\n");
}
DLinkNode* DLinklistFind(DLinkNode* head,DLinkType value)//查找值为value的结点
{
if(head == NULL)//非法操作
return;
DLinkNode* cur = head->next;
while(cur != head)
{
if(cur->data == value)
return cur;
cur = cur->next;
}
return NULL;
}
void DLinklistInsertBefore(DLinkNode* head,DLinkNode* pos,DLinkType value)//向pos位置前插入元素
{
if(head == NULL || pos == NULL)//非法操作
return;
DLinkNode* new_node = CreateDLinkNode(value);
DLinkNode* pre = pos->prev;
pre->next = new_node;
new_node->prev = pre;
new_node->next = pos;
pos->prev = new_node;
return;
}
void DLinklistInsertAfter(DLinkNode* head,DLinkNode* pos,DLinkType value)//向pos位置后插入元素
{
if(head == NULL || pos == NULL)//非法操作
return;
DLinkNode* new_node = CreateDLinkNode(value);
DLinkNode* next_node = pos->next;
pos->next = new_node;
new_node->prev = pos;
new_node->next = next_node;
next_node->prev = new_node;
return;
}
void DLinklistErase(DLinkNode* head,DLinkNode* pos)//删除pos位置的结点
{
if(head == NULL || pos == NULL)//非法操作
return;
if(head == pos)//非法操作,head指向的元素不能释放,除非在销毁整个链表
return;
DLinkNode* pre = pos->prev;
DLinkNode* nex = pos->next;
pre->next = nex;
nex->prev = pre;
DestroyNode(pos);
return;
}
void DLinklistRemove(DLinkNode* head,DLinkType value)//删除值为value的结点
{
if(head == NULL)
return;
DLinkNode* cur = head->next;
while(cur != head)
{
if(cur->data == value)
{
DLinkNode* pre = cur->prev;
DLinkNode* nex = cur->next;
pre->next = nex;
nex->prev = pre;
DestroyNode(cur);
return;
}
cur = cur->next;
}
return;
// DLinkNode* to_delete = DLinklistFind(head,value);
// if(to_delete == NULL)
// return;
// DLinklistErase(head,to_delete);
// return;
}
void DLinklistRemoveAll(DLinkNode* head,DLinkType value)//删除值为value的所有结点
{
if(head == NULL)
return;
DLinkNode* cur = head->next;
while(cur != head)
{
if(cur->data == value)
{
DLinkNode* pre = cur->prev;
DLinkNode* nex = cur->next;
pre->next = nex;
nex->prev = pre;
DestroyNode(cur);
}
cur = cur->next;
}
return;
}
void DLinklistDestroy(DLinkNode** phead)//销毁整个链表
{
if(phead == NULL)
return;
DLinkNode* cur = (*phead)->next;
while(cur != *phead)
{
DLinkNode* nex = cur->next;
DestroyNode(cur);
cur = nex;
}
DestroyNode(*phead);//要将头结点也销毁
*phead = NULL;//置空,避免成为野指针
}
void TestInit()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
printf("excepted is 0,actual is %d\n",(int)head->data);//初始化中的0用%c打印不出来,这里用%d,且要进行强转为int,防止发生错误
}
void TestPushBack()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushBack(head,'a');
DLinklistPushBack(head,'b');
DLinklistPushBack(head,'c');
DLinklistPushBack(head,'d');
DLinklistPushBack(head,'e');
DLinklistPrint(head,"尾插五个元素");
}
void TestPopBack()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushBack(head,'a');
DLinklistPushBack(head,'b');
DLinklistPushBack(head,'c');
DLinklistPushBack(head,'d');
DLinklistPrint(head,"尾插四个元素");
DLinklistPopBack(head);
DLinklistPopBack(head);
DLinklistPrint(head,"尾删两个元素");
DLinklistPopBack(head);
DLinklistPopBack(head);
DLinklistPrint(head,"再尾删两个元素");
}
void TestPushFront()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'b');
DLinklistPushFront(head,'c');
DLinklistPushFront(head,'d');
DLinklistPushFront(head,'e');
DLinklistPrint(head,"头插五个元素");
}
void TestPopFront()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'b');
DLinklistPushFront(head,'c');
DLinklistPushFront(head,'d');
DLinklistPrint(head,"头插五个元素");
DLinklistPopFront(head);
DLinklistPopFront(head);
DLinklistPrint(head,"头删两个元素");
DLinklistPopFront(head);
DLinklistPopFront(head);
DLinklistPrint(head,"再头删两个元素");
}
void TestFind()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'b');
DLinklistPushFront(head,'c');
DLinklistPushFront(head,'d');
DLinklistPushFront(head,'e');
DLinklistPrint(head,"头插五个元素");
DLinkNode* ret = DLinklistFind(head,'c');
printf("[%c|%p]\n",ret->data,ret);
DLinkNode* ret1 = DLinklistFind(head,'h');
if(ret1 == NULL)
printf("没找到\n");
else
printf("[%c|%p]\n",ret1->data,ret1);
}
void TestInsert()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushBack(head,'a');
DLinklistPushBack(head,'b');
DLinklistPushBack(head,'c');
DLinklistPushBack(head,'d');
DLinklistPrint(head,"尾插五个元素");
DLinkNode* pos = head->next;
DLinklistInsertBefore(head,pos,'h');
DLinklistPrint(head,"向a前插入h");
pos = head;
DLinklistInsertBefore(head,pos,'z');
DLinklistPrint(head,"向head前插入z");
pos = head->prev;
DLinklistInsertAfter(head,pos,'l');
DLinklistPrint(head,"在最后一个结点之后插入l");
}
void TestErase()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'b');
DLinklistPushFront(head,'c');
DLinklistPushFront(head,'d');
DLinklistPrint(head,"头插五个元素");
DLinkNode* pos = head;
DLinklistErase(head,pos);
DLinklistPrint(head,"删除head");
pos = head->next->next;
DLinklistErase(head,pos);
DLinklistPrint(head,"删除c");
pos = head->prev;
DLinklistErase(head,pos);
DLinklistPrint(head,"删除a");
}
void TestRemove()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'b');
DLinklistPushFront(head,'c');
DLinklistPushFront(head,'d');
DLinklistPrint(head,"头插五个元素");
DLinklistRemove(head,0);
DLinklistPrint(head,"删除0");
DLinklistRemove(head,'a');
DLinklistPrint(head,"删除a");
DLinklistRemove(head,'d');
DLinklistPrint(head,"删除d");
}
void TestRemoveAll()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'c');
DLinklistPushFront(head,'a');
DLinklistPrint(head,"头插五个元素");
DLinklistRemoveAll(head,'a');
DLinklistPrint(head,"删除a");
}
void TestDestroy()
{
SHOW_NAME;
DLinkNode* head;
DLinklistInit(&head);
DLinklistPushFront(head,'a');
DLinklistPushFront(head,'b');
DLinklistPushFront(head,'c');
DLinklistPushFront(head,'d');
DLinklistPushFront(head,'e');
DLinklistPrint(head,"头插五个元素");
DLinklistDestroy(&head);
}
int main()
{
TestInit();
TestPushBack();
TestPopBack();
TestPushFront();
TestPopFront();
TestFind();
TestInsert();
TestErase();
TestRemove();
TestRemoveAll();
TestDestroy();
return 0;
}