无头单向非循环链表
什么是链表?
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
我们在日常生活种用的最多的就是以下两种:
链表简介
无头单向非循环链表:结构简单,一般不会单独用,是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试种出现很多。
带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了。
无头单向非循环链表实现
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SCL;
我们在结构体里面不能直接将typedef重定义的结构体名,又重新在结构体里面用,比如下面这样就不可取:
typedef struct SListNode
{
SLTDataType data;
SCL next;
}SCL;
主要功能的接口:
// 动态申请一个节点
SCL* BuySListNode(SLTDataType x);
// 单链表打印
void SListPrint(SCL* phead);
// 单链表尾插
void SListPushBack(SCL** pphead, SLTDataType x);
// 单链表的头插
void SListPushFront(SCL** pphead, SLTDataType x);
// 单链表的尾删
void SListPopBack(SCL** pphead);
// 单链表头删
void SListPopFront(SCL** pphead);
// 单链表查找
SCL* SListFind(SCL* phead, SLTDataType x);
// 单链表在pos位置之后插入x
void SListInsertAfter(SCL* pos, SLTDataType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SCL* pos);
// 在pos之前插入
void SListInsert(SCL** pphead, SCL* pos, SLTDataType x);
// 删除pos位置
void SListErase(SCL** pphead, SCL* pos);
单链表增加与删除
// 动态申请一个节点
SCL* BuySListNode(SLTDataType x)
{
SCL* newnode = (SCL*)malloc(sizeof(SCL));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
头插头删
// 单链表的头插
void SListPushFront(SCL** pphead, SLTDataType x)
{
assert(pphead);
SCL* newnode = BuySListNode(x);
//假如链表为空,也能正常运行
newnode->next = *pphead;
*pphead = newnode;
}
// 单链表的头删
void SListPopFront(SCL** pphead)
{
assert(pphead);
assert(*pphead != NULL);
SCL* cur = *pphead;
*pphead = (*pphead)->next;
free(cur);
cur = NULL;
}
尾插尾删
// 单链表的尾插
void SListPushBack(SCL** pphead, SLTDataType x)
{
assert(pphead);
SCL* newnode = BuySListNode(x);
//1.空
if (*pphead==NULL)
{
*pphead = newnode;
}
//2.非空
else
{
//找单链表尾部
SCL* Tail = *pphead;
while (Tail->next!=NULL)
{
Tail = Tail->next;
}
Tail->next = newnode;
}
}
// 单链表的尾删
void SListPopBack(SCL** pphead)
{
assert(pphead);
// 暴力检查
assert(*pphead != NULL);
// 1、一个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
// 2、多个节点
else
{
SCL* tail = *pphead;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
单链表查找
// 单链表查找
SCL* SListFind(SCL* phead, SLTDataType x)
{
SCL* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
单链表更改
POS位置之后插入X
// 单链表在pos位置之后插入x
void SListInsertAfter(SCL* pos, SLTDataType x)
{
assert(pos);
SCL* newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
POS位置之前插入X
// 在pos之前插入
void SListInsert(SCL** pphead, SCL* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SListPushFront(pphead,x);
}
else
{
SCL* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
//如果直到cur为空也没有与pos匹配,那么直接断言报错
assert(cur);
}
SCL* newnode = BuySListNode(x);
newnode->next = pos;
cur->next = newnode;
}
}
POS位置之后删除
// 单链表删除pos位置之后的值
void SListEraseAfter(SCL* pos)
{
assert(pos);
if (pos->next == NULL)
{
return;
}
else
{
SCL* next = pos->next;
pos->next = next->next;
free(next);
next = NULL;
}
}
删除POS位置的值
// 删除pos位置
void SListErase(SCL** pphead, SCL* pos)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SListPopFront(pphead);
}
else
{
SCL* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
//如果没找到,直接报错
assert(cur);
}
cur->next = pos->next;
free(pos);
pos = NULL;
}
}
头文件代码
#pragma once
#include<stdio.h>
#include<assert.h>
#include <stdlib.h>
// 1、无头+单向+非循环链表增删查改实现
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SCL;
// 动态申请一个节点
SCL* BuySListNode(SLTDataType x);
// 单链表打印
void SListPrint(SCL* phead);
// 单链表尾插
void SListPushBack(SCL** pphead, SLTDataType x);
// 单链表的头插
void SListPushFront(SCL** pphead, SLTDataType x);
// 单链表的尾删
void SListPopBack(SCL** pphead);
// 单链表头删
void SListPopFront(SCL** pphead);
// 单链表查找
SCL* SListFind(SCL* phead, SLTDataType x);
// 单链表在pos位置之后插入x
void SListInsertAfter(SCL* pos, SLTDataType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SCL* pos);
// 在pos之前插入
void SListInsert(SCL** pphead, SCL* pos, SLTDataType x);
// 删除pos位置
void SListErase(SCL** pphead, SCL* pos);
函数实现代码
#include "SList.h"
// 动态申请一个节点
SCL* BuySListNode(SLTDataType x)
{
SCL* newnode = (SCL*)malloc(sizeof(SCL));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
// 单链表打印
void SListPrint(SCL* phead)
{
SCL* cur = phead;
while (cur!=NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
// 单链表尾插
void SListPushBack(SCL** pphead, SLTDataType x)
{
assert(pphead);
SCL* newnode = BuySListNode(x);
//1.空
if (*pphead==NULL)
{
*pphead = newnode;
}
//2.非空
else
{
//找单链表尾部
SCL* Tail = *pphead;
while (Tail->next!=NULL)
{
Tail = Tail->next;
}
Tail->next = newnode;
}
}
// 单链表的头插
void SListPushFront(SCL** pphead, SLTDataType x)
{
assert(pphead);
SCL* newnode = BuySListNode(x);
//假如链表为空,也能正常运行
newnode->next = *pphead;
*pphead = newnode;
}
// 单链表的尾删
void SListPopBack(SCL** pphead)
{
//第一种
//assert(pphead);
//assert(*pphead != NULL);
//SCL* Tail = *pphead;
//SCL* cur = *pphead;
//if (cur->next == NULL)
//{
// free(cur);
// cur = NULL;
//}
//while (cur->next->next != NULL)
//{
// cur = cur->next;
//}
//Tail = cur->next;
//cur->next = NULL;
//free(Tail);
//Tail = NULL;
//第二种
assert(pphead);
// 温柔的检查
if (*pphead == NULL)
{
return;
}
// 暴力检查
//assert(*pphead != NULL);
// 1、一个节点
// 2、多个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SCL* tail = *pphead;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
// 单链表头删
void SListPopFront(SCL** pphead)
{
assert(pphead);
assert(*pphead != NULL);
SCL* cur = *pphead;
*pphead = (*pphead)->next;
free(cur);
cur = NULL;
}
// 单链表查找
SCL* SListFind(SCL* phead, SLTDataType x)
{
SCL* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
// 单链表在pos位置之后插入x
void SListInsertAfter(SCL* pos, SLTDataType x)
{
assert(pos);
SCL* newnode = BuySListNode(x);
//第一种方法
//SCL* cur = pos->next;
//pos->next = newnode;
//newnode->next = cur;
//第二种方法
newnode->next = pos->next;
pos->next = newnode;
}
// 单链表删除pos位置之后的值
void SListEraseAfter(SCL* pos)
{
assert(pos);
if (pos->next == NULL)
{
return;
}
else
{
SCL* next = pos->next;
pos->next = next->next;
free(next);
next = NULL;
}
}
// 在pos之前插入
void SListInsert(SCL** pphead, SCL* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SListPushFront(pphead,x);
}
else
{
SCL* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
//如果直到cur为空也没有与pos匹配,那么直接断言报错
assert(cur);
}
SCL* newnode = BuySListNode(x);
newnode->next = pos;
cur->next = newnode;
}
}
// 删除pos位置
void SListErase(SCL** pphead, SCL* pos)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SListPopFront(pphead);
}
else
{
SCL* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
//如果没找到,直接报错
assert(cur);
}
cur->next = pos->next;
free(pos);
pos = NULL;
}
}
如果发现错误欢迎大佬们指出😸😸