欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

不带头结点的单链表之增删查改

程序员文章站 2024-03-21 13:49:04
...

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;
}