目录
前言
链表和顺序表它们都属于线性表。并且它们之间存在互补关系。
1、什么是链表?
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。
结构展示(如下图所示)
2、链表的实现(以带头结点的链表实例)
2.1链表的定义以及内存开辟
typedef int SLlistDataType;
typedef struct SList
{
//数据域
SLlistDataType data;
//指针域
struct SList* next;
}SList;
//内存开辟
SList* CreatStorage()
{
SList* SLNode = NULL;
SLNode = (SList*)malloc(sizeof(SList));
return SLNode;
}
2.2链表的插入
2.2.1链表的尾插
注意:这里函数的形参使用二级指针来接收。如果直接用指针接收只是将实参的值进行了拷贝,并不会改变实参的值(同利用函数交换两个数的值的原理一样)。
void SListTailInsert(SList** phead, SLlistDataType x)
{
SList* NewNode;
SList* TailNode;
//当链表为空链表
if ((*phead)->next == NULL)
{
NewNode = CreatStorage();
NewNode->data = x;
NewNode->next = NULL;
//连接结点
(*phead)->next = NewNode;
}
//链表不为空
else
{
TailNode = (*phead);
//查找尾节点
while (TailNode->next != NULL)
{
TailNode = TailNode->next;
}
NewNode = CreatStorage();
NewNode->data = x;
//将尾结点的指针域交给新结点的指针域
NewNode->next = TailNode->next;
//连接新结点
TailNode->next = NewNode;
}
}
2.2.2链表的头插
void SListHeadInsert(SList** phead, SLlistDataType x)
{
//无论该链表是否为空
SList* NewNode = CreatStorage();
NewNode->data = x;
NewNode->next = (*phead)->next;
(*phead)->next = NewNode;
}
2.2.3链表的随机插入
void SListRandomInsert(SList** phead, SLlistDataType x, int ItemNode)
{
int count = 0;
int flag = 0;
//移动结点
SList* SearchNode = NULL;
//记录目标结点的前一个结点
SList* PriorNode = (*phead);
SList* NewNode = CreatStorage();
SearchNode = (*phead)->next;
//已经指向第一个节点
count = 1;
while (SearchNode != NULL)
{
if (count == ItemNode)
{
flag = 1;
NewNode->data = x;
//连接结点
NewNode->next = PriorNode->next;
PriorNode->next = NewNode;
return;
}
else
{
PriorNode = SearchNode;
SearchNode = SearchNode->next;
count++;
}
}
if (!flag)
{
printf("链表中无该节点\n");
}
}
2.3链表的删除
2.3.1链表的尾删
void SListTailDelete(SList** phead)
{
SList* FirstNode = (*phead)->next;
//如果是空链表
if (FirstNode == NULL)
{
return;
}
else if (FirstNode->next == NULL)
{
//只有一个结点
(*phead)->next = FirstNode->next;
//释放结点的空间
free(FirstNode);
}
else
{
//尾结点
SList* TailNode;
//记录尾结点的前一个结点
SList* PriorNode = NULL;
//先指向链表的第一个节点,之后开始移动到尾节点
TailNode = (*phead)->next;
while (TailNode->next != NULL)
{
//将TailNode存放的结点先给PriorNode
PriorNode = TailNode;
TailNode = TailNode->next;
}
PriorNode->next = TailNode->next;
//将尾结点的空间释放
free(TailNode);
}
}
2.3.2链表的头删
void SListHeadDelete(SList** phead)
{
if ((*phead)->next == 0)
{
return;
}
else
{
SList* FirstNode = (*phead)->next;
(*phead)->next = FirstNode->next;
free(FirstNode);
}
}
2.3.3链表的随机删除
void SListRandomDelete(SList** phead, int ItemNode)
{
int count = 0;
int flag = 0;
//移动结点
SList* SearchNode = NULL;
//记录目标结点的前一个结点
SList* PriorNode = (*phead);
SearchNode = (*phead)->next;
//已经指向第一个节点
count = 1;
while (SearchNode != NULL)
{
if (count == ItemNode)
{
flag = 1;
PriorNode->next = SearchNode->next;
free(SearchNode);
return;
}
else
{
PriorNode = SearchNode;
SearchNode = SearchNode->next;
count++;
}
}
if (!flag)
{
printf("链表中无该节点\n");
}
}
2.4链表的输出
void ShowSList(SList* phead)
{
if (phead->next == NULL)
{
printf("NULL\n");
return;
}
else
{
phead = phead->next;
while (phead != NULL)
{
printf("%d->", phead->data);
phead = phead->next;
}
printf("NULL\n");
}
}
3、总结
优点:1.插入和删除很快,不需要挪动数据。
2.不需要扩容,不会造成空间浪费。
缺点:1.不能随机访问数据
完整代码(不含测试代码)
头文件
#pragma once
#include <stdio.h>
#include <stdlib.h>
typedef int SLlistDataType;
typedef struct SList
{
//数据域
SLlistDataType data;
//指针域
struct SList* next;
}SList;
//尾插法
void SListTailInsert(SList** phead, SLlistDataType x);
//头插法
void SListHeadInsert(SList** phead, SLlistDataType x);
//查找数据(x代表要查找的数据)
void SListSearchData(SList* phead, SLlistDataType x);
//尾删数据
void SListTailDelete(SList** phead);
//头删数据
void SListHeadDelete(SList** phead);
//任意插入数据
void SListRandomInsert(SList** phead, SLlistDataType x, int ItemNode);//插入的位置
//任意删除数据
void SListRandomDelete(SList** phead, int ItemNode);
//链表输出
void ShowSList(SList* phead);
//开辟内存
SList* CreatStorage();
功能实现
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
void SListTailInsert(SList** phead, SLlistDataType x)
{
SList* NewNode;
SList* TailNode;
//当链表为空链表
if ((*phead)->next == NULL)
{
NewNode = CreatStorage();
NewNode->data = x;
NewNode->next = NULL;
//连接结点
(*phead)->next = NewNode;
}
//链表不为空
else
{
TailNode = (*phead);
//查找尾节点
while (TailNode->next != NULL)
{
TailNode = TailNode->next;
}
NewNode = CreatStorage();
NewNode->data = x;
//将尾结点的指针域交给新结点的指针域
NewNode->next = TailNode->next;
//连接新结点
TailNode->next = NewNode;
}
}
void SListHeadInsert(SList** phead, SLlistDataType x)
{
//无论该链表是否为空
SList* NewNode = CreatStorage();
NewNode->data = x;
NewNode->next = (*phead)->next;
(*phead)->next = NewNode;
}
void SListSearchData(SList* phead, SLlistDataType x)
{
SList* SearchNode = phead->next;
int flag = 0;//作为标记数
int NodeCount = 0;//统计结点数
while (SearchNode != NULL)
{
NodeCount++;
if (SearchNode->data == x)
{
flag = 1;
printf("找到数据为%d,位于第 %d 结点\n", SearchNode->data, NodeCount);
SearchNode = SearchNode->next;
}
else
{
flag = 0;
SearchNode = SearchNode->next;
}
}
if(!flag)
printf("没有这个数据\n");
}
void SListTailDelete(SList** phead)
{
SList* FirstNode = (*phead)->next;
//如果是空链表
if (FirstNode == NULL)
{
return;
}
else if (FirstNode->next == NULL)
{
//只有一个结点
(*phead)->next = FirstNode->next;
//释放结点的空间
free(FirstNode);
}
else
{
//尾结点
SList* TailNode;
//记录尾结点的前一个结点
SList* PriorNode = NULL;
//先指向链表的第一个节点,之后开始移动到尾节点
TailNode = (*phead)->next;
while (TailNode->next != NULL)
{
//将TailNode存放的结点先给PriorNode
PriorNode = TailNode;
TailNode = TailNode->next;
}
PriorNode->next = TailNode->next;
//将尾结点的空间释放
free(TailNode);
}
}
void SListHeadDelete(SList** phead)
{
if ((*phead)->next == 0)
{
return;
}
else
{
SList* FirstNode = (*phead)->next;
(*phead)->next = FirstNode->next;
free(FirstNode);
}
}
void SListRandomInsert(SList** phead, SLlistDataType x, int ItemNode)
{
int count = 0;
int flag = 0;
//移动结点
SList* SearchNode = NULL;
//记录目标结点的前一个结点
SList* PriorNode = (*phead);
SList* NewNode = CreatStorage();
SearchNode = (*phead)->next;
//已经指向第一个节点
count = 1;
while (SearchNode != NULL)
{
if (count == ItemNode)
{
flag = 1;
NewNode->data = x;
//连接结点
NewNode->next = PriorNode->next;
PriorNode->next = NewNode;
return;
}
else
{
PriorNode = SearchNode;
SearchNode = SearchNode->next;
count++;
}
}
if (!flag)
{
printf("链表中无该节点\n");
}
}
void SListRandomDelete(SList** phead, int ItemNode)
{
int count = 0;
int flag = 0;
//移动结点
SList* SearchNode = NULL;
//记录目标结点的前一个结点
SList* PriorNode = (*phead);
SearchNode = (*phead)->next;
//已经指向第一个节点
count = 1;
while (SearchNode != NULL)
{
if (count == ItemNode)
{
flag = 1;
PriorNode->next = SearchNode->next;
free(SearchNode);
return;
}
else
{
PriorNode = SearchNode;
SearchNode = SearchNode->next;
count++;
}
}
if (!flag)
{
printf("链表中无该节点\n");
}
}
void ShowSList(SList* phead)
{
if (phead->next == NULL)
{
printf("NULL\n");
return;
}
else
{
phead = phead->next;
while (phead != NULL)
{
printf("%d->", phead->data);
phead = phead->next;
}
printf("NULL\n");
}
}
SList* CreatStorage()
{
SList* SLNode = NULL;
SLNode = (SList*)malloc(sizeof(SList));
return SLNode;
}