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

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
#include
#include
#include

//初始化 在函数操作的过程中,如果需要修改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;

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

 

你可能感兴趣的:(数据结构,c语言初阶,c++,c语言,数据结构)