头文件 SListNode.h
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
typedef int DataType;
typedef struct SListNode
{
DataType data; //链表中存放的数据
struct SListNode *pNextNode; //指向下一节点的指针
}SListNode, *PSListNode;
// 初始化单链表(对于无头结点单链表,该函数没有意义)
void InitList(PSListNode* pHead);
// 销毁单链表
void DestroyList(PSListNode* pHead);
// 尾插
void PushBack(PSListNode* pHead, DataType data);
// 尾出
void PopBack(PSListNode* pHead);
// 头插
void PushFront(PSListNode* pHead, DataType data);
// 头出
void PopFront(PSListNode* pHead);
// 在链表中查找元素data
PSListNode Find(PSListNode pHead, DataType data);
// 删除pos位置的结点(注意不能用那种替换形式)
void Erase(PSListNode* pHead, PSListNode pos);
// 在链表的pos位置插入元素data
void Insert(PSListNode* pHead, PSListNode pos, DataType data);
//打印链表存放的数据
void PrintList(PSListNode pHead);
主程序 ListNode.c
#include "SListNode.h"
//这儿的参数是二级指针,因为要对结构体指针的内容进行修改,所以必须传该指针的地址(即一个二级指针)
//传一级指针的话相当于是值传递,不会对实参有改变
void InitList(PSListNode* pHead)
{
assert(pHead);
*pHead = NULL;
}
PSListNode ByeNode(DataType data)
{
PSListNode pNewNode = (PSListNode)malloc(sizeof(struct SListNode));
if (NULL != pNewNode)
{
pNewNode->data = data;
//注意使开辟的新节点的指向为空
pNewNode->pNextNode = NULL;
}
return pNewNode;
}
void PushBack(PSListNode* pHead, DataType data)
{
PSListNode pNode = NULL;
PSListNode pNewNode = NULL;
assert(pHead);
if (NULL == (*pHead))
{
//此时可以不对ByeNode函数是否成功开辟空间做检测,因为即使它没有开辟成功空间,
//那么使头结点头结点等于NULL逻辑一样正确
*pHead = ByeNode(data);
}
else
{
pNode = *pHead;
//找到尾节点
while (NULL != pNode->pNextNode)
{
//保存尾节点
pNode = pNode->pNextNode;
}
pNewNode = ByeNode(data);
//当开辟空间失败,说明向链表里插入了一个空指针
pNode->pNextNode = pNewNode;
}
}
void PopBack(PSListNode* pHead)
{
PSListNode pPerNode = NULL;
PSListNode pCurNode = NULL;
assert(pHead);
if (NULL == (*pHead))
{
printf("链表中没有数据节点!\n");
}
else
{
pCurNode = *pHead;
//注意循环结束的条件
while (NULL != pCurNode->pNextNode)
{
pPerNode = pCurNode;
pCurNode = pCurNode->pNextNode;
}
//把要删除的结点从链表中断开(让该节点的上一个结点指向该结点的下一个结点)
pPerNode->pNextNode = NULL;
//删除该结点
free(pCurNode);
pCurNode = NULL;
}
}
void PushFront(PSListNode* pHead, DataType data)
{
assert(pHead);
if (NULL == (*pHead))
{
//此时可以不对ByeNode函数是否成功开辟空间做检测,因为即使它没有开辟成功空间,
//那么使头结点头结点等于NULL逻辑一样正确
*pHead = ByeNode(data);
}
else
{
PSListNode pNewNode = ByeNode(data);
if (NULL == pNewNode)
{
printf("开辟节点空间失败!\n");
}
else
{
//使指向头结点的指针指向新开辟的节点,新开辟的节点指向链表中原来的头结点
pNewNode->pNextNode = *pHead;
*pHead = pNewNode;
}
}
}
void PopFront(PSListNode* pHead)
{
assert(pHead);
if (NULL == (*pHead))
{
printf("链表中没有数据节点!\n");
}
else
{
PSListNode pNode = *pHead;
//直接使头结点指向链表中第三个节点,即可做到头删的目的
*pHead = (*pHead)->pNextNode;
free(pNode);
pNode = NULL;
}
}
PSListNode Find(PSListNode pHead, DataType data)
{
PSListNode pNode = pHead;
while (NULL != pNode)
{
if (pNode->data == data)
{
return pNode;
}
else
{
pNode = pNode->pNextNode;
}
}
//没有找到对应的结点
return NULL;
}
void Erase(PSListNode* pHead, PSListNode pos)
{
//更简单的方法(pos指向的结点在链表中):
//直接交换pos指向的节点和pos指向的节点的下一个结点的数据,然后使pos指向的节点的下一个结点为它的下下一个结点
PSListNode pCurNode = *pHead;
PSListNode pPerNode = *pHead;
assert(pHead);
if (NULL == pos)
{
return;
}
//要是传的参数没有在链表中,那么删除就显得没有意义了,因此对pos的检测(pos是否是链表中的某个节点)可有可无
while ((pCurNode != pos) && (pCurNode != NULL))
{
pPerNode = pCurNode;
pCurNode = pCurNode->pNextNode;
}
//使当前结点的上一个结点指向当前结点的下一个结点,然后释放当前结点的空间,即可做到删除当前结点
pPerNode->pNextNode = pPerNode->pNextNode->pNextNode;
free(pCurNode);
pCurNode = NULL;
}
void Insert(PSListNode* pHead, PSListNode pos, DataType data)
{
//更简单的方法(pos指向的结点在链表中):
//直接交换pos指向的节点和新插入的节点的的数据,然后使新插入的结点的下一个结点为pos指向的节点的下一个结点,
//pos指向的节点的下一个结点为新插入的结点
PSListNode pTempNode = *pHead;
PSListNode pNode = *pHead;
assert(pHead);
//pTempNode!=NULL是为了避免pos是一个创建的孤结点,它没有插入到链表中
while ((pTempNode != pos) && (pTempNode != NULL))
{
pNode = pTempNode;
pTempNode = pTempNode->pNextNode;
}
if ((pTempNode == NULL) && (pos != NULL))
{
printf("链表中不存在该结点!\n");
return;
}
else
{
PSListNode pNewNode = ByeNode(data);
if (NULL == pNewNode)
{
printf("开辟空间失败!\n");
}
else
{
pNewNode->pNextNode = pNode->pNextNode;
pNode->pNextNode = pNewNode;
}
}
}
void PrintList(PSListNode pHead)
{
PSListNode pNode = pHead;
//当pHead指向空时,说明此时链表中没有数据,那么不会进入打印数据的循环,而是等到函数结束返回
while (NULL != pNode)
{
printf("%d ", pNode->data);
pNode = pNode->pNextNode;
}
printf("\n");
}
void DestroyList(PSListNode* pHead)
{
PSListNode pCurNode = NULL;
PSListNode pPerNode = *pHead;
assert(pHead);
while (NULL != pCurNode)
{
//每次销毁链表最前面那个结点的空间
pPerNode = pCurNode->pNextNode;
free(pCurNode);
//不会出现野指针
pCurNode = pPerNode;
}
}
测试函数 test.c
#include "SListNode.h"
//Test PushBack() / PopBack()
void TestFun1()
{
PSListNode pHead = NULL;
InitList(&pHead);
PushBack(&pHead, 0);
PushBack(&pHead, 1);
PushBack(&pHead, 2);
PushBack(&pHead, 3);
PrintList(pHead);
PopBack(&pHead);
PopBack(&pHead);
PrintList(pHead);
}
//Test PushFront() / PopFront()
void TestFun2()
{
PSListNode pHead = NULL;
InitList(&pHead);
PushFront(&pHead, 0);
PushFront(&pHead, 1);
PushFront(&pHead, 2);
PushFront(&pHead, 3);
PrintList(pHead);
PopFront(&pHead);
PopFront(&pHead);
PrintList(pHead);
}
//Test Find() / Erase() / Insert()
void TestFun3()
{
PSListNode pHead = NULL;
PSListNode pRetNode = NULL;
InitList(&pHead);
PushBack(&pHead, 0);
PushBack(&pHead, 1);
PushBack(&pHead, 2);
PushBack(&pHead, 3);
PrintList(pHead);
pRetNode = Find(pHead, 2);
printf("%d\n", pRetNode->data);
Erase(&pHead, Find(pHead, 1));
PrintList(pHead);
Insert(&pHead, Find(pHead, 2), 1);
PrintList(pHead);
}
//Test DestroyList()
void TestFun4()
{
PSListNode pHead = NULL;
InitList(&pHead);
PushBack(&pHead, 0);
PushBack(&pHead, 1);
PushBack(&pHead, 2);
PushBack(&pHead, 3);
DestroyList(&pHead);
PrintList(pHead);
}
int main()
{
//TestFun1();
//TestFun2();
//TestFun3();
TestFun4();
system("pause");
return 0;
}