一、概念
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
在现实数据结构中:
1.链式结构在逻辑上是连续的,但在物理上不一定连续。
2.现实中的结点一般是从堆上申请出来的。
3.从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,也可能不连续。
链表分类:
1.单向或双向
2.带头或不带头
3.循环或非循环
常用的链表结构为:无头单向非循环链表和带头双向循环链表。
二、结构体定义
//不带头单向非循环链表
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);// 单链表查找
void SListInsertAfter(SListNode* pos, SLTDateType x);// 单链表在pos位置之后插入x
void SListEraseAfter(SListNode* pos);// 单链表删除pos位置之后的值
void SListDestory(SListNode** plist);// 单链表的销毁
因为实现的是不带头结点的单链表,在函数中需要直接对指针进行操作,所以大部分操作函数传参都需要传递二级指针。
1.动态申请一个个结点
通过malloc动态申请结点,并初始化数据域为x,指针域初始化为空。
SListNode* BuySListNode(SLTDateType x) {// 动态申请一个节点x
SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
if (newNode == NULL) {//申请失败
assert(0);
return NULL;
}
newNode->data = x;
newNode->next = NULL;
return newNode;
}
2.打印单链表
void SListPrint(SListNode* plist) {//打印单链表
assert(plist);
SListNode* node = plist;
while (node) {
printf("%d-->", node->data);
node = node->next;
}
printf("NULL");
}
3.单链表尾插
对于不带头的单链表,每次插入都需要考虑到链表为空的特殊情况。
void SListPushBack(SListNode** pplist, SLTDateType x) {// 单链表尾插
assert(pplist);
SListNode* newNode = BuySListNode(x);//动态申请一个结点x
if (*pplist == NULL) {//链表初始为空
*pplist = newNode;
}
else {//链表非空
SListNode* cur = *pplist;
while (cur->next) {
cur = cur->next;
}
cur->next = newNode;
}
}
4.单链表头插
void SListPushFront(SListNode** pplist, SLTDateType x) {// 单链表的头插
assert(*pplist);
SListNode* newNode = BuySListNode(x);//动态申请一个结点x
if (*pplist == NULL) {
*pplist = newNode;
}
else {
newNode->next = *pplist;
*pplist = newNode;
}
}
5.单链表尾删
对于不带头的单链表的删除,也需考虑链表为空和只有一个结点两种特殊情况。
void SListPopBack(SListNode** pplist) {// 单链表的尾删
assert(pplist);
if (*pplist == NULL) {//空链表
return;
}
else if ((*pplist)->next == NULL) {//链表只有一个结点
free(*pplist);
*pplist = NULL;
}
else {
SListNode* cur = *pplist;
SListNode* prev = NULL;
while (cur->next) {
prev = cur;
cur = cur->next;
}
free(cur);
prev->next = NULL;
}
}
6.单链表头删
void SListPopFront(SListNode** pplist) {// 单链表头删
assert(*pplist);
if (*pplist == NULL) {//空链表
return;
}
else if ((*pplist)->next == NULL) {//链表只有一个结点
free(*pplist);
*pplist = NULL;
}
else {
SListNode* cur = *pplist;
*pplist = cur->next;
free(cur);
}
}
7.单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x) {// 单链表查找
assert(plist);
SListNode* cur = plist;
while (cur) {
if (cur->data == x) {
return cur;
}
cur = cur->next;
}
return NULL;
}
8.单链表任意位置插入
void SListInsertAfter(SListNode* pos, SLTDateType x) {// 单链表在pos位置之后插入x
assert(pos);
if (pos == NULL) {
return;
}
SListNode* newNode = BuySListNode(x);
newNode->next = pos->next;
pos->next = newNode;
}
9.单链表任意位置删除
void SListEraseAfter(SListNode* pos) {// 单链表删除pos位置之后的值
assert(pos);
if (pos == NULL||pos->next==NULL) {
return;
}
SListNode* newNode = NULL;
newNode = pos->next;
pos->next = newNode->next;
free(newNode);
}
10.单链表销毁
void SListDestory(SListNode** pplist) {// 单链表的销毁
assert(pplist);
SListNode* cur = *pplist;
while (cur) {
*pplist = cur->next;
free(cur);
cur = *pplist;
}
}
四、代码测试
1.测试用例
void SListtest() {
SListNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPushBack(&plist, 5);
SListPushFront(&plist, 0);
SListInsertAfter(SListFind(plist, 3), 99);
SListPrint(plist);
printf("\n");
SListEraseAfter(SListFind(plist, 3));
SListPrint(plist);
printf("\n");
SListPopBack(&plist);
SListPopFront(&plist);
SListPrint(plist);
SListDestory(&plist);
}
2.测试结果
五、完整代码
#include<stdio.h>
#include<malloc.h>
#include<string.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);// 单链表查找
void SListInsertAfter(SListNode* pos, SLTDateType x);// 单链表在pos位置之后插入x
void SListEraseAfter(SListNode* pos);// 单链表删除pos位置之后的值
void SListDestory(SListNode** plist);// 单链表的销毁
void SListtest() {
SListNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPushBack(&plist, 5);
SListPushFront(&plist, 0);
SListInsertAfter(SListFind(plist, 3), 99);
SListPrint(plist);
printf("\n");
SListEraseAfter(SListFind(plist, 3));
SListPrint(plist);
printf("\n");
SListPopBack(&plist);
SListPopFront(&plist);
SListPrint(plist);
SListDestory(&plist);
}
int main() {
SListtest();
return 0;
}
SListNode* BuySListNode(SLTDateType x) {// 动态申请一个节点x
SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
if (newNode == NULL) {//申请失败
assert(0);
return NULL;
}
newNode->data = x;
newNode->next = NULL;
return newNode;
}
void SListPrint(SListNode* plist) {//打印单链表
assert(plist);
SListNode* node = plist;
while (node) {
printf("%d-->", node->data);
node = node->next;
}
printf("NULL");
}
void SListPushBack(SListNode** pplist, SLTDateType x) {// 单链表尾插
assert(pplist);
SListNode* newNode = BuySListNode(x);//动态申请一个结点x
if (*pplist == NULL) {//链表初始为空
*pplist = newNode;
}
else {//链表非空
SListNode* cur = *pplist;
while (cur->next) {
cur = cur->next;
}
cur->next = newNode;
}
}
void SListPushFront(SListNode** pplist, SLTDateType x) {// 单链表的头插
assert(*pplist);
SListNode* newNode = BuySListNode(x);//动态申请一个结点x
if (*pplist == NULL) {
*pplist = newNode;
}
else {
newNode->next = *pplist;
*pplist = newNode;
}
}
void SListPopBack(SListNode** pplist) {// 单链表的尾删
assert(pplist);
if (*pplist == NULL) {//空链表
return;
}
else if ((*pplist)->next == NULL) {//链表只有一个结点
free(*pplist);
*pplist = NULL;
}
else {
SListNode* cur = *pplist;
SListNode* prev = NULL;
while (cur->next) {
prev = cur;
cur = cur->next;
}
free(cur);
prev->next = NULL;
}
}
void SListPopFront(SListNode** pplist) {// 单链表头删
assert(*pplist);
if (*pplist == NULL) {//空链表
return;
}
else if ((*pplist)->next == NULL) {//链表只有一个结点
free(*pplist);
*pplist = NULL;
}
else {
SListNode* cur = *pplist;
*pplist = cur->next;
free(cur);
}
}
SListNode* SListFind(SListNode* plist, SLTDateType x) {// 单链表查找
assert(plist);
SListNode* cur = plist;
while (cur) {
if (cur->data == x) {
return cur;
}
cur = cur->next;
}
return NULL;
}
void SListInsertAfter(SListNode* pos, SLTDateType x) {// 单链表在pos位置之后插入x
assert(pos);
if (pos == NULL) {
return;
}
SListNode* newNode = BuySListNode(x);
newNode->next = pos->next;
pos->next = newNode;
}
void SListEraseAfter(SListNode* pos) {// 单链表删除pos位置之后的值
assert(pos);
if (pos == NULL||pos->next==NULL) {
return;
}
SListNode* newNode = NULL;
newNode = pos->next;
pos->next = newNode->next;
free(newNode);
}
void SListDestory(SListNode** pplist) {// 单链表的销毁
assert(pplist);
SListNode* cur = *pplist;
while (cur) {
*pplist = cur->next;
free(cur);
cur = *pplist;
}
}