目录
一 概念及其结构
二 双向链表的实现
1 List.h 包含一下我们想要的接口
2 初始化,扩容和打印(List.c)
3 尾插(List.c)
4 尾删(List.c)
5 头插(List.c)
6 头删(List.c)
7 找pos位置(List.c)
8 在pos位置插入x(List.c)
9 删除pos位置(List.c)
10 测试(Test.c)
单链表
双链表(带头)
1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了,后面我们代码实现了就知道了
#pragma once
#include
#include
#include
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
LTDataType data;
}LTNode;
//扩容
LTNode* BuyLTNode(LTDataType x);
//初始化
LTNode* LTInit();
//打印
void LTPrint(LTNode* phead);
//尾插尾删
void LTPushBack(LTNode* phead, LTDataType x);
void LTPopBack(LTNode* phead);
//头插头删
void LTPushFront(LTNode* phead, LTDataType x);
void LTPopFront(LTNode* phead);
//链表大小
int LTSize(LTNode* phead);
//找位置
LTNode* LTFind(LTNode* phead, LTDataType x);
// 在pos位置插入x
void LTInsert(LTNode* pos, LTDataType x);
// 删除pos位置
void LTErase(LTNode* pos);
//扩容
LTNode* BuyLTNode(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;
}
//初始化
LTNode* LTInit()
{
LTNode* phead = BuyLTNode(0);
phead->next = phead;
phead->prev = phead;
return phead;
}
//打印
void LTPrint(LTNode* phead)
{
assert(phead);
printf("phead->");
LTNode* cur = phead;
while (cur->next != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyLTNode(x);
LTNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
free(tail);
phead->prev = tailPrev;
tailPrev->next = phead;
}
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyLTNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
LTNode* first = phead->next;
LTNode* second = first->next;
free(first);
phead->next = second;
second->prev = phead;
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
LTNode* cur = phead->next;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
// 在pos位置插入x
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = BuyLTNode(x);
LTNode* posPrev = pos->prev;
posPrev->next = newnode;
newnode->prev = posPrev;
newnode->next = pos;
pos->prev = newnode;
}
// 删除pos位置
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
free(pos);
posPrev->next = posNext;
posNext->prev = posPrev;
}
#include"List.h"
void Test1()
{
LTNode* plist = LTInit();
LTPushBack(plist, 1);
LTPushBack(plist, 2);
LTPushBack(plist, 3);
LTPushBack(plist, 4);
LTPushBack(plist, 5);
LTPrint(plist);
LTPopBack(plist);
LTPrint(plist);
LTPushFront(plist, 40);
LTPrint(plist);
LTPopFront(plist);
LTPrint(plist);
LTNode* pos1 = LTFind(plist, 4);
LTInsert(pos1, 50);
LTPrint(plist);
LTNode* pos2 = LTFind(plist, 50);
LTErase(pos2);
LTPrint(plist);
}
int main()
{
Test1();
return 0;
}
感觉理解链表的原理 实现起来其实不难 下一个博客我将对链表这一块的常规题目进行整理 继续加油!