//头文件 //List.h #pragma once #include#include #include #include typedef int LTDataType; typedef struct ListNode { struct ListNode* next; struct ListNode* prev; LTDataType data; }LTNode; //利用二级指针 //void ListInit(LTNode** pphead); //利用返回值 LTNode* ListInit(); void ListPrint(LTNode* phead); //尾插 void ListPushBack(LTNode* phead, LTDataType x); //头插 void ListPushFront(LTNode* phead, LTDataType x); //尾删 void ListPopBack(LTNode* phead); //头删 void ListPopFront(LTNode* phead); //判断链表是否为空 bool ListEmpty(LTNode* phead); //在pos位置之前插入x void ListInsert(LTNode* pos, LTDataType x); //删除pos位置的节点 void ListErase(LTNode* pos); //求链表的长度 bool ListEmpty(LTNode* phead); int ListSize(LTNode* phead); //双向链表的销毁 void ListDestory(LTNode* plist);
//源文件
//List.c
#include "List.h"
LTNode* BuyListNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc fail");
exit(-1);
}
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
//void ListInit(LTNode** pphead)
//{
// *pphead = BuyListNode(-1);
// (*pphead)->next = *pphead;
// (*pphead)->prev = *pphead;
//}
LTNode* ListInit()
{
LTNode* phead = BuyListNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
void ListPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("n");
}
//尾插
void ListPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
ListInsert(phead, x);
}
//头插
void ListPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
//LTNode* newnode = BuyListNode(x);
//LTNode* next = phead->next;
phead newnode next
//phead->next = newnode;
//newnode->prev = phead;
//newnode->next = next;
//next->prev = newnode;
ListInsert(phead->next, x);
}
//尾删
void ListPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
assert(!ListEmpty(phead));
//LTNode* tail = phead->prev;
//LTNode* tailPrev = tail->prev;
//free(tail);
//tailPrev->next = phead;
//phead->prev = tailPrev;
ListErase(phead->prev);
}
//头删
void ListPopFront(LTNode* phead)
{
assert(phead);
ListErase(phead->next);
}
//判断链表是否为空
bool ListEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
//在pos位置之前插入x
void ListInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* newnode = BuyListNode(x);
//prev newnode
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
//删除pos位置的节点
void ListErase(LTNode* pos)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* next = pos->next;
prev->next = next;
next->prev = prev;
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;
int size = 0;
while (cur != phead)
{
LTNode* next = cur->next;
ListErase(cur);
cur = next;
}
free(phead);
phead = NULL;
}
//源文件
//test.c
#include "List.h"
void TestList1()
{
//LTNode* plist = NULL;
//ListInit(&plist);
LTNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushBack(plist, 4);
ListPushBack(plist, 5);
ListPrint(plist);
}
void TestList2()
{
//LTNode* plist = NULL;
//ListInit(&plist);
LTNode* plist = ListInit();
ListPushFront(plist, 1);
ListPushFront(plist, 2);
ListPushFront(plist, 3);
ListPushFront(plist, 4);
ListPushFront(plist, 5);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListDestory(plist);
plist = NULL;
}
int main()
{
TestList1();
return 0;
}
2.顺序表和带头双向循环链表的区别
| 不同点 | 顺序表 | 链表 |
| 存储空间上 | 物理上一定连续 | 逻辑上连续,但物理上不一定连续 |
| 随机访问 | 支持O(1) | 不支持:O(N) |
| 任意位置插入或者删除元素 | 可能需要搬移元素,效率低O(N) | 只需修改指针指向 |
| 插入 | 动态顺序表,效率不够高时需要扩容 | 没有容量的概念 |
| 应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
| 缓存利用率高低 | 高 | 低 |
顺序表的优点:下标随机访问、CPU高速缓存命中率高。
顺序表的缺点:头部或者中间插入删除效率低,扩容(有一定程度性能消耗、可能存在一定程度的空间浪费)。
链表的优点:任意位置插入删除O(1),按需申请释放。
链表的缺点:不支持下标的随机访问。



