目录
(一)链表的概念
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
(二)链表的分类
分类:(1)单向或者双向;(2)带头或者不带头;(3)循环或非循环
虽然结构很多,但本文主要将两种链表:(1)无头单向非循环链表;(2)带头双向循环链表。
(1)无头单向非循环链表
无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。
(2)带头双向循环链表
概念:带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带
来很多优势,实现反而简单了。
(三)代码实现
(1)无头单向非循环链表:(后续不再实现菜单)
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);
// 单链表的销毁
void SListDestroy(SListNode** pplist);
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* NewNode = (SListNode*)malloc(sizeof(SListNode));
if (NewNode == NULL)
{
perror("BuySListNode");
}
NewNode->data = x;
NewNode->next = NULL;
return NewNode;
}
// 单链表打印
void SListPrint(SListNode* plist)
{
SListNode* tmp = plist;
while (tmp)
{
printf("%d->", tmp->data);
tmp = tmp->next;
}
printf("NULL\n");
}
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
assert(pplist);
SListNode* NewNode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = NewNode;
}
else
{
SListNode* p = *pplist;
while (p->next != NULL)
{
p = p->next;
}
p->next = NewNode;
}
}
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
assert(pplist);
SListNode* NewNode = BuySListNode(x);
NewNode->next = *pplist;
*pplist = NewNode;
}
// 单链表的尾删
void SListPopBack(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* p = *pplist;
SListNode* q = *pplist;
while (p->next != NULL)
{
q = p;
p = p->next;
}
q->next = NULL;
free(p);
}
}
// 单链表头删
void SListPopFront(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* p = (*pplist)->next;
free(*pplist);
*pplist = p;
}
}
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
assert(plist);
SListNode* p = plist;
while (p != NULL)
{
if (p->data == x)
{
return p;
}
p = p->next;
}
return NULL;
}
// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* NewNode = BuySListNode(x);
NewNode->next = pos->next;
pos->next = NewNode;
}
// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
assert(pos);
SListNode* p = pos->next->next;
free(pos->next);
pos->next = p;
}
// 单链表的销毁
void SListDestroy(SListNode** pplist)
{
assert(pplist);
SListNode* p = *pplist;
while (*pplist != NULL)
{
*pplist = (*pplist)->next;
free(p);
p = *pplist;
}
*pplist = NULL;
}
void menu()
{
printf("*****************************************\n");
printf("***** 1.头插 2.尾插 *****\n");
printf("***** 3.头删 4.尾删 *****\n");
printf("***** 5.插入 6.删除 *****\n");
printf("***** 7.输出 0.退出 *****\n");
printf("*****************************************\n");
}
int main()
{
int input = 0;
SListNode* SL = NULL, *pos = NULL;
do
{
int val = 0, tmp = 0;
menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入插入元素的值\n");
scanf("%d", &val);
SListPushFront(&SL, val);
break;
case 2:
printf("请输入插入元素的值\n");
scanf("%d", &val);
SListPushBack(&SL, val);
break;
case 3:
SListPopFront(&SL);
break;
case 4:
SListPopBack(&SL);
break;
case 5:
printf("请输入插入元素的值与位置(值)\n");
scanf("%d %d", &val, &tmp);
pos = SListFind(SL,tmp);
SListInsertAfter(pos, val);
break;
case 6:
printf("请输入删除元素前的值\n");
scanf("%d", &val);
pos = SListFind(SL, val);
SListEraseAfter(pos);
break;
case 7:
SListPrint(SL);
break;
case 0:
printf("退出程序\n");
SListDestroy(&SL);
break;
default:
printf("请重新选择\n");
break;
}
} while (input);
return 0;
}
(2)带头双向循环链表
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
//创建新结点
ListNode* CreateNode(LTDataType x);
// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
//创建结点
ListNode* CreateNode(LTDataType x)
{
ListNode* tmp = (ListNode*)malloc(sizeof(ListNode));
if (tmp == NULL)
{
perror("CreateNode fail");
return NULL;
}
tmp->data = x;
tmp->prev = NULL;
tmp->next = NULL;
return tmp;
}
// 创建返回链表的头结点.
ListNode* ListCreate()
{
ListNode* head = (ListNode*)malloc(sizeof(ListNode));
if (head == NULL)
{
perror("malloc fail");
return NULL;
}
head->next = head;
head->prev = head;
return head;
}
// 双向链表销毁
void ListDestory(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
ListNode* next = cur->next;
free(cur);
cur = next;
}
free(pHead);
}
// 双向链表打印
void ListPrint(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
printf("head<=>");
while (cur != pHead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead);
//创建新结点
ListNode* NewNode = CreateNode(x);
ListNode* tail = pHead->prev;
//插入
tail->next = NewNode;
NewNode->prev = tail;
NewNode->next = pHead;
pHead->prev = NewNode;
}
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
assert(pHead);
assert(!(pHead->next == pHead));
ListNode* tail = pHead->prev;
ListNode* prev = tail->prev;
//删除
pHead->prev = prev;
prev->next = pHead;
free(tail);
}
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead);
//创建结点
ListNode* NewNode = CreateNode(x);
if (NewNode == NULL)
{
perror("CreateNode fail");
return;
}
//插入结点
ListNode* next = pHead->next;
pHead->next = NewNode;
NewNode->prev = pHead;
next->prev = NewNode;
NewNode->next = next;
}
// 双向链表头删
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(!(pHead->next == pHead));
ListNode* cur = pHead->next;
ListNode* next = pHead->next->next;
pHead->next = next;
next->prev = pHead;
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* prev = pos->prev;
ListNode* NewNode = CreateNode(x);
if (NewNode == NULL)
{
perror("CreateNode fail");
}
prev->next = NewNode;
NewNode->prev = prev;
pos->prev = NewNode;
NewNode->next = pos;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* prev = pos->prev;
ListNode* next = pos->next;
prev->next = next;
next->prev = prev;
free(pos);
}
void Test1()
{
//初始化
ListNode* head = ListCreate();
//尾插
ListPushBack(head, 1);
ListPushBack(head, 2);
ListPushBack(head, 3);
ListPushBack(head, 4);
ListPrint(head);
//尾删
ListPopBack(head);
ListPopBack(head);
ListPrint(head);
//尾删
ListPopBack(head);
ListPopBack(head);
ListPrint(head);
//尾插
ListPushBack(head, 1);
ListPushBack(head, 2);
ListPushBack(head, 3);
ListPushBack(head, 4);
ListPrint(head);
//销毁
ListDestory(head);
head = NULL;
}
void Test2()
{
//初始化
ListNode* head = ListCreate();
//头插
ListPushFront(head, 4);
ListPushFront(head, 3);
ListPushFront(head, 2);
ListPushFront(head, 1);
ListPrint(head);
//头删
ListPopFront(head);
ListPopFront(head);
ListPrint(head);
ListPopFront(head);
ListPopFront(head);
ListPrint(head);
//头插
ListPushFront(head, 4);
ListPushFront(head, 3);
ListPushFront(head, 2);
ListPushFront(head, 1);
ListPrint(head);
//销毁
ListDestory(head);
head = NULL;
}
void Test3()
{
//初始化
ListNode* head = ListCreate();
//尾插
ListPushBack(head, 1);
ListPushBack(head, 2);
ListPushBack(head, 3);
ListPushBack(head, 4);
ListPushBack(head, 5);
ListPrint(head);
//插入
ListNode* tmp = ListFind(head, 3);
ListInsert(tmp, 0);
ListPrint(head);
tmp = NULL;
//删除
tmp = ListFind(head, 4);
ListErase(tmp);
ListPrint(head);
tmp = NULL;
//销毁
ListDestory(head);
head = NULL;
}
int main()
{
Test1(); //初始化+尾插+尾删+销毁
Test2(); //初始化+头插+头删+销毁
Test3(); //初始化+尾插+插入+删除+销毁
return 0;
}