1.构造结构体,创建结点
这里重命名int是为了适应多种情况,若存的数据类型是char只需要改一个地方就行
结构体内容是数据与下一个结点的地址
SLTNode是结构体重命名后的名字
typedef int SLTDataType;
typedef struct SListNode {
SLTDataType data;
struct SListNode* next;
}SLTNode;
2.尾插的实现
尾插先判断链表是否为空,若为空就直接把得到的新节点作为头结点
下面为创建结点的函数,避免重复写创建结点的代码
SLTNode* BuyNode(SLTDataType x)
{
SLTNode* tmp = (SLTNode*)malloc(sizeof(SLTNode));
if (tmp == NULL)
{
perror("malloc fail:");
return NULL;
}
tmp->data = x;
tmp->next = NULL;
return tmp;
}
若链表不为空,就去找尾结点的位置,这里设置cur是避免用*pphead后找不到头的位置,若cur的next不为空就一直往下一个结点走,直到走到最后一个,再把新的结点接上
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuyNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* cur = *pphead;
while (cur->next)
{
cur = cur->next;
}
cur->next = newnode;
}
}
3.头插的实现
先判断链表是否为空,如果不为空就把头指针指向新结点就完成了
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuyNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
newnode->next = *pphead;
*pphead = newnode;
}
}
4.尾删的实现
先判断链表是否为空,为空就直接free头结点,不为空就要去找尾结点,但是不仅要尾结点,还需要尾结点的前一个结点,因为链表的最后一个结点的next是要指向NULL,free了尾结点,倒数第二个结点成为尾结点,但是它的next是指向free的那个结点(因为free只会释放结点的空间,指向还是那个空间,只是没有权限访问),所以需要找倒数第一和第二的结点位置
//尾删
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* next = *pphead;
SLTNode* cur = *pphead;
while (cur->next)
{
next = cur;
cur=cur->next;
}
free(cur);
cur = NULL;
next->next = NULL;
}
}
5.头删的实现
先判断链表是否为单个,若为单个就直接free,不为单个就先设置一个变量来存储头结点的下一个结点的位置,然后free头结点,在把头指针指向存储的变量
//头删
void SLTPopFront(SLTNode** pphead)
{
assert(pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* cur = (*pphead)->next;
free(*pphead);
*pphead = cur;
}
}
6.查找的实现
查找就是对比数据data是否一样,就是遍历链表就完成
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
assert(phead);
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
7.在指定的位置前插入数据
在指定的位置之前插入需要找到指定结点的前一个结点位置,当while循环结束后,cur的下一个结点就是指定的结点,只需要把新结点的next接到pos上(一个结点可以被多个指针指),然后把cur的下一个指向newnode新结点就完成了
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
SLTNode* newnode = BuyNode(x);
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
newnode->next = pos;
cur->next = newnode;
}
8.在指定的位置之后插入数据
需要把新结点的下一个接到pos的下一个结点上,然后把pos的下一个接到新结点上
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuyNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
9.删除pos结点
删除一个结点需要找到删除的结点以及其前一个结点,因为要把删除的结点和删除结点的下一个结点接起来
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
cur->next = pos->next;
free(pos);
pos = NULL;
}
10.删除pos之后的结点
删除pos之后的结点需要把pos的next与删除的next的结点连接起来
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
assert(pos);
SLTNode* cur = pos->next;
pos->next = cur->next;
free(cur);
cur = NULL;
}
11.销毁链表
先设置俩个变量,一个用来free,一个来遍历,直至把链表都删完
//销毁链表
void SListDesTroy(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
12.总代码
test.c
#include"SList.h"
int main()
{
SLTNode* s;
s = NULL;
SLTPushBack(&s, 1);
SLTPushBack(&s, 2);
SLTPushBack(&s, 3);
SLTPushBack(&s, 4);
SLTPushBack(&s, 5);
SLTPushBack(&s, 6);
SLTNode* cur=SLTFind(s, 2);
SLTInsert(&s, cur, 33);
SLTInsertAfter(cur, 44);
SLTPushFront(&s, 11);
//SLTPopFront(&s);
//SLTPopBack(&s);
//SLTErase(&s, cur);
//SLTEraseAfter(cur);
SLTPrint(s);
return 0;
}
SList.h
#pragma once
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义节点的结构
//数据 + 指向下一个节点的指针
typedef int SLTDataType;
typedef struct SListNode {
SLTDataType data;
struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);
SList.c
#include"SList.h"
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur)
{
printf("%d ", cur->data);
cur = cur->next;
}
}
SLTNode* BuyNode(SLTDataType x)
{
SLTNode* tmp = (SLTNode*)malloc(sizeof(SLTNode));
if (tmp == NULL)
{
perror("malloc fail:");
return NULL;
}
tmp->data = x;
tmp->next = NULL;
return tmp;
}
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuyNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* cur = *pphead;
while (cur->next)
{
cur = cur->next;
}
cur->next = newnode;
}
}
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuyNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
newnode->next = *pphead;
*pphead = newnode;
}
}
//尾删
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* next = *pphead;
SLTNode* cur = *pphead;
while (cur->next)
{
next = cur;
cur=cur->next;
}
free(cur);
cur = NULL;
next->next = NULL;
}
}
//头删
void SLTPopFront(SLTNode** pphead)
{
assert(pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* cur = (*pphead)->next;
free(*pphead);
*pphead = cur;
}
}
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
assert(phead);
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
SLTNode* newnode = BuyNode(x);
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
newnode->next = pos;
cur->next = newnode;
}
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuyNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
cur->next = pos->next;
free(pos);
pos = NULL;
}
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
assert(pos);
SLTNode* cur = pos->next;
pos->next = cur->next;
free(cur);
cur = NULL;
}
//销毁链表
void SListDesTroy(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}