单链表 C语言代码+注释 如果对你有帮助:点赞+收藏+评论+关注~ 感谢!欢迎各位与博主友好讨论!
单链表相比顺序表优点:用指针将各个结点串在一起。
单链表缺点:查找任意位置的结点地址时很麻烦。
头文件 S.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;//指针
}SLTNode;
//打印
void SlistPrint(SLTNode* phead);
//创建空间
SLTNode* CreatSListNode(SLTDataType x);
//尾插
void SListPushBack(SLTNode**pphead, SLTDataType x);
//头插
void SListPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SListPopBack(SLTNode** pphead);
//头删
void SListPopFront(SLTNode** pphead);
//查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x);
//任意的pos节点前面插入
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//任意pos节点删除
void SListErase(SLTNode** pphead, SLTNode* pos);
函数实现 S.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "S.h"
//打印
void SlistPrint(SLTNode* phead)
{
SLTNode* current = phead;
while (current != NULL)
{
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n\n");
}
//开辟空间
SLTNode* CreatSListNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//尾插
void SListPushBack(SLTNode** pphead, SLTDataType x)
//(SLTNode*phead, ) pphead是phead(plist)的地址,*pphead是phead的内容
{
/*SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
newnode->data = x;
newnode->next = NULL;*/
SLTNode* newnode=CreatSListNode(x);
if (*pphead == NULL)//phead==NULL
{
*pphead = newnode;
}
else
{//找尾节点的指针
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
//尾结点,链接新节点
tail->next = newnode;
}
}
//头插
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = CreatSListNode(x);
newnode->next = *pphead;//先前头结点的地址放入现在新的头结点
*pphead = newnode;//把新的第一个结点地址给phead
}
//尾删
void SListPopBack(SLTNode** pphead)
{
//1.空链表,就别删了
if (*pphead == NULL)
{
return ;
}
//2.只有一个结点,注意空指针
else if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
//3.一个以上结点
else
{
SLTNode* prev = NULL;
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
prev->next = NULL;
}
}
//头删
void SListPopFront(SLTNode** pphead)
{
SLTNode* next = (*pphead)->next;//把第二个结点的地址给保存起来
//如果直接释放,不保存下一个的地址的话:头结点里还保存着下一个节点地址,这样就会找不到第二个结点了
free(*pphead);//释放第一个结点
*pphead = next;//把保存好的第二个结点的地址放入定义的头指针
}
//查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
SLTNode* current = phead;
while (current != NULL)
{
if (current->data == x)
{
return current;
}
current = current->next;
}
return NULL;
}
//任意的pos节点前面插入
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
SLTNode* newnode = CreatSListNode(x);
if (pos == *pphead)//只有一个结点
{
SListPushFront(pphead, x);//就当做头插
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = newnode;
newnode->next = pos;
}
}
//任意pos节点删除
void SListErase(SLTNode** pphead, SLTNode* pos)
{
if (pos == *pphead)
{
SListPopFront(pphead);//当只有一个结点,没有前一个结点,使用头删
}
SLTNode* prev = *pphead;//prev是pos的前一个结点
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
测试 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "S.h"
void TestSlist1()
{
SLTNode* plist = NULL;//第一个节点指针置为空
SListPushBack(&plist, 1); //实参传递地址,改变形参才会改变实参
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPushFront(&plist, 0);
SlistPrint(plist);
//SListPopFront(&plist);
//SListPopFront(&plist);
//SListPopFront(&plist);
//SListPopFront(&plist);
SListPopFront(&plist);
//SlistPrint(plist);
//
//SListPopBack(&plist);
//SlistPrint(plist);
//在2前面插入20
SLTNode* pos = SListFind(plist,2);
if (pos)
{
SListInsert(&plist,pos,20);
}
SlistPrint(plist);
pos = SListFind(plist, 20);
if (pos)
{
SListErase(&plist, pos);
}
SlistPrint(plist);
}
int main()
{
TestSlist1();
return 0;
}