【C】单链表

来源:互联网 发布:淘宝网店技巧 编辑:程序博客网 时间:2024/05/18 00:53

头文件 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);// 在链表中查找元素dataPSListNode Find(PSListNode pHead, DataType data);// 删除pos位置的结点(注意不能用那种替换形式)void  Erase(PSListNode* pHead, PSListNode pos);// 在链表的pos位置插入元素datavoid  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;}




原创粉丝点击