不带头结点的单链表之增删查改
Posted I am Supreme
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不带头结点的单链表之增删查改相关的知识,希望对你有一定的参考价值。
SList.h
#pragma once
typedef int DataTepe;
typedef struct SListNode
{
DataTepe data;
struct SListNode* next;
}Node;
//初始化
void SListInit(Node **head);
//尾插
void SListPushBack(Node **head,DataTepe data);
//尾删
void SListPopBack(Node **head);
//头删 -------------------没写完
void SListPopFront(Node **head);
//头插
void SListPushFront(Node **head, DataTepe data);
//查找
Node* SListFind(Node *head, DataTepe data);
//任意位置删除
void SListErase(Node *pos);
//任意位置插入
void SListInsert(Node *pos, DataTepe data);
//链表的容量
int SListSize(Node*head);
//链表的销毁
void SListDestry(Node**head);
//******************打印*****************
void printList(Node* head);
SList.c
#include"SList.h"
#include<stdio.h>
#include<assert.h>
#include<malloc.h>
#include<stdlib.h>
//初始化 在函数操作的过程中,如果需要修改head的指向,必须传递二级指针
void SListInit(Node **head)
{
//此时head一定不为空
assert(head);
*head = NULL;//因为是二级指针 解引用一级指针让它指向空
}
Node*BuyListNode(DataTepe data)
{
Node * node = (Node*)malloc(sizeof(Node));
if (NULL == node)
{
exit(0);
return NULL;
}
node->data = data;
node->next = NULL;
return node;
}
//尾插
void SListPushBack(Node **head, DataTepe data)
{
//分两种情况 1、链表为空的情况/2、链表非空
//1、空链表--->链表已经存在,但是链表中没有有效节点
assert(head);//先判断head是否为空:非法情况时assert为空
if (NULL == *head)//记得解引用 因为传进来是二级指针
*head = BuyListNode(data);//指向新的节点
//2、链表非空---> 2.1找到链表中最后一个节点 2.2插入
else
{
Node*cur = *head;
while (cur->next)
{
cur = cur->next;
}
cur->next = BuyListNode(data);
}
}
//尾删 //head是二级指针,说明head中放置的是外部实参的地址 *head才指向的是第一个节点即头指针
void SListPopBack(Node **head)
{
//分3种情况 1、链表为空 链表非空时存在两种可能 2链表只有一个节点 3链表有多个节点
//1、链表为空 则直接返回
assert(head);
if (NULL == *head)
return;
//2、链表非空
//只有一个节点 则释放节点,然后让head指向NULL
else if (NULL == (*head)->next)
{
free(*head);
*head = NULL;
}
//3、有多个节点,找到最后一个节点 删除不能直接删除否则找不到上一个节点了
//3.1找到最后一个节点保存上一个节点
//3.2删除需要删除的节点
//3.3将上一个节点的next指向NULL
else
{
Node*cur = *head;
Node*prev = NULL;//用来保存前一个指针
while (cur->next)
{
prev = cur;//保存cur的上一个节点
cur = cur->next;
}
prev->next = NULL;
free(cur);
}
}
//头删
void SListPopFront(Node **head)
{
//分3种情况 1、链表为空 链表非空时存在两种可能 2链表只有一个节点 3链表有多个节点
//1、空链表 则直接返回
Node * delNode = NULL;//用之前先声明
assert(head);
if (NULL == *head)
return;
//2、链表只有一个节点 则释放该节点 让head置空
#if 0
else if (NULL == (*head)->next)
{
free(head);
head = NULL;
}
#endif
//3、链表有多个节点 定义一个需要删除的节点 让head 指向delNode的next指向,释放需要删除的节点
else
{
//这步操作可以处理第二种情况
delNode = *head;
*head = delNode->next;
free(delNode);
}
}
//头插
void SListPushFront(Node **head, DataTepe data)
{
//如果是空链表,则让head指向新的节点
assert(head);//先判断head是否为空:非法情况时assert为空
Node*newnode = BuyListNode(data);
//非空,则先让新节点指向原来的第一个节点再让head指向NewNode(两种情况解决情况相同)
newnode->next = *head;
*head = newnode;
}
//查找
Node* SListFind(Node *head,DataTepe data)
{
Node*cur = head;
while (cur)
{
if (data == cur->data)
return cur;
cur = cur->next;
}
return NULL;
}
//任意位置删除 只能删除pos之后的节点
void SListErase(Node *pos)
{
Node*delNode;
if (NULL == pos||NULL==pos->next)
return;
delNode = pos->next;
pos->next = delNode->next;
free(delNode);
}
//任意位置插入
void SListInsert(Node *pos, DataTepe data)
{
Node* newnode = NULL;
//1、先判断pos这个位置是否合法
if (NULL == pos)
return;
//2、只能插入到pos之后,单链表找不到前节点
else
{
newnode = BuyListNode(data);
newnode->next = pos->next;
pos->next = newnode;
}
}
//链表的容量
int SListSize(Node*head)
{
int count = 0;
Node *cur = head;
while (cur)
{
++count;
cur = cur->next;
}
return count;
}
//链表的销毁
void SListDestry(Node**head)
{
//直接使用头删 一个一个删
Node*delNode = NULL;
assert(head);
while (NULL != *head)
{
delNode = *head;//把第一个节点标记起来
*head = delNode->next;
free(delNode);
}
}
//******************打印*****************
void printList(Node* head)
{
Node *cur = head;
while (cur)
{
printf("%d--->", cur->data);
cur = cur->next;
}
printf("NULL\\n");
}
20210513.c
#include"SList.h"
#include<stdio.h>;
void testList()
{
Node*head;//定义一个链表 给一个结点类型的指针
//head = NULL; 在这儿是可以的 但注意:想要通过对形参的修改达到外部实参的目的,在传参的时候,需要传递实参的地址
SListInit(&head);
//尾插
SListPushBack(&head, 1);
SListPushBack(&head, 2);
SListPushBack(&head, 3);
SListPushBack(&head, 4);
SListPushBack(&head, 5);
printList(head);
//尾删
SListPopBack(&head);
printList(head);
SListPopBack(&head);
printList(head);
SListPopBack(&head);
printList(head);
//头删
SListPopFront(&head);
SListPopFront(&head);
printList(head);
//头插
SListPushFront(&head, 6);
SListPushFront(&head, 7);
SListPushFront(&head, 8);
printList(head);
//任意位置的插入 7的位置传入10
SListInsert(SListFind(head,6), 10);
printList(head);
//任意位置的删除
SListErase(SListFind(head, 6));
printList(head);
//容量
printf("有%d个节点,\\n",SListSize(head));
//链表用完一定记得销毁
SListDestry(&head);
return 0;
}
int main()
{
testList();
return 0;
}
以上是关于不带头结点的单链表之增删查改的主要内容,如果未能解决你的问题,请参考以下文章
数据结构学习笔记(单链表单循环链表带头双向循环链表)的增删查改排序等)
数据结构学习笔记(单链表单循环链表带头双向循环链表)的增删查改排序等)