List.h(函数声明)
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* prev;
LTDataType val;
struct ListNode* next;
}LTNode;
//创建哨兵位头结点并返回该结点
LTNode* ListCreate();
//尾插
void ListPushBack(LTNode* phead, LTDataType val);
//打印链表
void ListPrint(LTNode* phead);
//头插
void ListPushFront(LTNode* phead, LTDataType x);
//尾删
void ListPopBack(LTNode* phead);
//判断带头双向链表是否为NULL
bool ListEmpty(LTNode* phead);
//头删
void ListPopFront(LTNode* phead);
//任意结点之前插入x
void ListInsert(LTNode* pos, LTDataType x);
//删除任意结点
void ListErase(LTNode* pos);
//求链表的长度
int ListSize(LTNode* phead);
//销毁链表
void ListDestory(LTNode* phead);
//查找结点
LTNode* ListFind(LTNode* phead, LTDataType x);
List.c(函数实现)
#include"List.h"
//创建新结点
LTNode* BuyListNode(LTDataType val)
{
//堆区创建空间来存储数据,再将空间地址存储到指针中返回,供程序员使用。
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL)
{
//perror(malloc fail);
printf("malloc fail\n");
exit(-1);
}
newnode->next = NULL;
newnode->prev = NULL;
newnode->val = val;
return newnode;
}
//创建哨兵位头结点并返回该结点
LTNode* ListCreate()
{
//给哨兵位头结点的val赋值,赋值0也可以。
LTNode* phead = BuyListNode(-1);
(phead)->next = phead;
(phead)->prev = phead;
return phead;
}
//尾插
void ListPushBack(LTNode* phead, LTDataType x)
{
//防止phead为NULL
assert(phead);
//创建新结点
LTNode* newnode = BuyListNode(x);
//找尾结点
LTNode* tail = phead->prev;
//新结点与尾结点、哨兵位头结点相连。
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
//pos结点前插入函数代替尾插函数
//ListInsert(phead, x);
}
//打印链表
void ListPrint(LTNode* phead)
{
assert(phead);
//cur初始时为phead后一个结点
LTNode* cur = phead->next;
while (cur!=phead)
{
printf("%d ", cur->val);
cur = cur->next;
}
printf("\n");
}
//头插
void ListPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
//创建新结点
LTNode* newnode = BuyListNode(x);
//头插新结点,用head记录旧的头结点。
LTNode* head = phead->next;
//插入newhead结点
newnode->next = head;
head->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
//pos结点前插入函数代替头插函数
//ListInsert(phead->next, x);
}
//尾删
void ListPopBack(LTNode* phead)
{
assert(phead);
空链表时,唯一的结点哨兵位结点不能被释放
//assert(!ListEmpty(phead))
assert(phead->next!=phead);
//找旧尾结点
LTNode* tail = phead->prev;
//找新尾结点
LTNode* newtail = tail->prev;
//新尾结点与哨兵位头结点相连
newtail->next = phead;
phead->prev = newtail;
//释放旧的尾结点
free(tail);
//用删除pos结点函数进行尾删
//ListErase(phead->prev);
}
//判断带头双向链表是否为NULL
bool ListEmpty(LTNode* phead)
{
assert(phead);
//返回true表示为空链表
return phead->next == phead;
}
//头删
void ListPopFront(LTNode* phead)
{
assert(phead);
//空链表时,唯一的结点哨兵位结点不能被释放
assert(phead->next != phead);
//旧头结点
LTNode* head = phead->next;
//新头结点
LTNode* newhead = head->next;
//新头结点连接哨兵位头结点
phead->next = newhead;
newhead->prev = phead;
//释放旧的头结点
free(head);
//用删除pos结点函数进行头删
//ListErase(phead->next);
}
//pos结点之前插入x
void ListInsert(LTNode* pos, LTDataType x)
{
assert(pos);
//创建新的结点
LTNode* newnode = BuyListNode(x);
//标记将会成为newnode->prev的结点
LTNode* newnodePrev = pos->prev;
//插入newnode结点
newnodePrev->next = newnode;
newnode->next = pos;
pos->prev = newnode;
newnode->prev = newnodePrev;
}
//删除任意结点
void ListErase(LTNode* pos)
{
assert(pos);
//记录pos前后两个结点
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
//连接前后两个结点
posPrev->next = posNext;
posNext->prev = posPrev;
//释放pos结点
free(pos);
}
//求链表的长度
int ListSize(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
int size = 0;
while (cur!=phead)
{
size++;
cur = cur->next;
}
return size;
}
//销毁链表
void ListDestory(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur!=phead)
{
LTNode* tmp = cur->next;
free(cur);
cur = tmp;
}
free(phead);//plist的置空留给调用函数的人操作
}
//查找结点
LTNode* ListFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur!=phead)
{
if (cur->val == x)
return cur;
cur = cur->next;
}
printf("为找到该结点\n");
return NULL;
}
Test.c(函数测试)
#include"List.h"
void TestList1()//创建哨兵位结点、尾插、打印链表
{
//plist作为链表哨兵位头结点的指针,让其存储在其他函数中动态申请的有数据的空间地址。
LTNode* plist= ListCreate();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushBack(plist, 4);
ListPushBack(plist, 5);
ListPrint(plist);
}
void TestList2()//测试头插
{
LTNode* plist = ListCreate();
ListPushFront(plist, 5);
ListPushFront(plist, 4);
ListPushFront(plist, 3);
ListPushFront(plist, 2);
ListPushFront(plist, 1);
ListPrint(plist);
}
void TestList3()//测试尾删
{
LTNode* plist = ListCreate();
ListPushFront(plist, 5);
ListPushFront(plist, 4);
ListPushFront(plist, 3);
ListPushFront(plist, 2);
ListPushFront(plist, 1);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);//连删6次
}
void TestList4()//测试头删
{
LTNode* plist = ListCreate();
ListPushFront(plist, 5);
ListPushFront(plist, 4);
ListPushFront(plist, 3);
ListPushFront(plist, 2);
ListPushFront(plist, 1);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);//连删6次
}
void TestList5()//测试查找结点、pos结点之前插入、删除pos结点、求链表长度
{
LTNode* plist = ListCreate();
ListPushFront(plist, 5);
ListPushFront(plist, 4);
ListPushFront(plist, 3);
ListPushFront(plist, 2);
ListPushFront(plist, 1);
ListPrint(plist);
LTNode* ret = ListFind(plist, 3);
ListInsert(ret, 666);
ListPrint(plist);
ListErase(ret);
ListPrint(plist);
int length=ListSize(plist);
printf("链表长度为%d\n", length);
}
int main()
{
TestList1();
return 0;
}