SList.h
#pragma once
typedef int DataType;
//定义节点
typedef struct SListNode
{
DataType data;
struct SListNode* next; //指向下一个节点,类型也是struct SListNode
}Node;
//初始化
//在函数操作中,如果需要修改head的指向,必须传递二级指针
void SListInit(Node** head);
//对于尾插、头插,没有节点需要head指向其他;尾删、头删,如果只有一个节点,需要让head指向空
//尾插
void SListPushBack(Node** head, DataType data);
//尾删
void SListPopBack(Node** head);
//头插
void SListPushFront(Node** head, DataType data);
//头删
void SListPopFront(Node** head);
//任意位置的插入,不牵扯到head
void SListInsert(Node* pos, DataType data);
//任意位置的删除
void SListErase(Node* pos);
//获得有效元素的大小,遍历,不牵扯到head
int SListSize(Node* head);
//查找,注意返回的是节点
Node* SListFind(Node* head, DataType data);
//销毁,所有节点没有了,head需要指向空
void SListDestroy(Node** head);
//测试
void SListPrint(Node* head);
SList.c
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "SList.h"
// head表示链表, *head是操作链表(链表的首地址或者链表的首节点), **head是操作链表的第一个节点(即第一个元素的节点的地址)
//构造新节点(需要插入的节点和数)
Node* NewSListNode(DataType data)
{
Node* node = (Node*)malloc(sizeof(Node)); //开辟Node结构体的大小
if(NULL == node) //不能用assert
{
exit(0);
return NULL;
}
node->data = data;
node->next = NULL; //并不知道下一个节点是谁,给成空
return node;
}
//初始化
//在函数操作中,如果需要修改head的指向,必须传递二级指针。**head就是第一个元素的节点的地址
void SListInit(Node** head)
{
assert(head);
*head = NULL;
}
//尾插
void SListPushBack(Node** head, DataType data)
{
assert(head);
//1.当链表为空链表
if(NULL == *head)
{
*head = NewSListNode(data); //构造一个新的链表
}
else
{
//2.当链表非空
//2.1 找到链表中的最后一个节点
Node* cur = *head;
while(cur->next) //当cur->next == NULL,则cur是最后一个节点
{
cur = cur->next;
}
cur->next = NewSListNode(data);
}
}
//尾删
void SListPopBack(Node** head)
{
assert(head);
if(NULL == *head) //空链表,什么都没有
return;
else if(NULL == (*head)->next) //链表中只有一个节点
{
free(*head);
*head = NULL;
}
else //链表中有多个节点
{
//找到链表中最后一个节点,并保存其前一个节点,让其的下一个节点指向空
Node* cur = *head;
Node* pre = NULL; //用来保存最后一个节点的前一个节点
while(cur->next)
{
pre = cur; //pre是cur的前一个节点
cur = cur->next; //cur是最后一个节点
}
free(cur); // 释放掉最后一个节点
pre->next = NULL; //让pre的下一个节点指向空
}
}
//头插
void SListPushFront(Node** head, DataType data)
{
assert(head);
Node* newNode = NewSListNode(data);
newNode->next = *head; //第一步:让新节点的下一个节点指向第一个元素的节点
*head = newNode; //第二步:让新的节点成为第一个节点
}
//头删
void SListPopFront(Node** head)
{
Node* delNode = NULL; //声明变量delNode,不声明会出错
assert(head);
if(NULL == *head)
return;
delNode = *head; //先把第一个节点标记出来
*head = delNode->next; //让下一个节点成为第一个节点
free(delNode); //释放第一个元素的节点
}
//任意位置的插入,注意:只能往pos位置的后面插入,不能在pos位置之前插入,因为pos位置之前的节点并不知道
//如果要插入到pos之前,在执行上面的操作之后,只需交换两个节点的值域就可以
void SListInsert(Node* pos, DataType data)
{
Node* newNode = NULL;
if(NULL == pos)
return;
newNode = NewSListNode(data);
newNode->next = pos->next;
pos->next = newNode;
}
//任意位置的删除,只能删除pos位置之后的一个节点
//如果pos位置删除之后,就无法链接前面的节点
void SListErase(Node* pos)
{
Node* delNode = NULL;
if(NULL == pos || NULL == pos->next)
return;
delNode = pos->next;
pos->next = pos->next->next;
free(delNode);
}
//获取有效元素的大小
int SListSize(Node* head)
{
int count = 0;
Node* cur = head;
while(cur)
{
++count;
cur = cur->next;
}
return count;
}
//查找
Node* SListFind(Node* head, DataType data)
{
Node* cur = head;
while(cur)
{
if(data == cur->data)
return cur;
cur = cur->next;
}
return NULL; //没有找到这个节点,则返回空
}
//销毁,采用头删法进行销毁
void SListDestroy(Node** head)
{
Node* delNode = NULL;
assert(head);
while(NULL != *head)
{
delNode = *head;
free(delNode);
*head = delNode->next;
}
}
//测试
void SListPrint(Node* head)
{
Node* cur = head;
while(cur)
{
printf("%d--->",cur->data);
cur = cur->next;
}
printf("NULL\n");
}
test.c
#include <stdio.h>
#include "SList.h"
int main()
{
Node* head;
SListInit(&head); //head是指针,需要取地址
SListPushBack(&head, 1);
SListPushBack(&head, 2);
SListPushBack(&head, 3);
SListPushBack(&head, 4);
SListPushBack(&head, 5);
SListPushBack(&head, 6);
SListSize(head);
SListPrint(head);
SListPopBack(&head);
SListSize(head);
SListPrint(head);
SListPushFront(&head, 0);
SListPushFront(&head, 9);
SListSize(head);
SListPrint(head);
SListPopFront(&head);
SListSize(head);
SListPrint(head);
SListInsert(SListFind(head,3),8);
SListSize(head);
SListPrint(head);
SListErase(SListFind(head,2));
SListSize(head);
SListPrint(head);
return 0;
}
链表插入和删除的图例