单向不带头链表

单向不带头链表

一、单项不带头链表结构

1.什么是链表?
  我的理解是链表是一种逻辑上是线性结构,在真正的内存空间中是非线性,一般而言,不连续的结构,它是通过在堆区一块一块申请空间,用指针把各块空间连起来的结构,也就保存各块空间的地址来连接!!!
  下面给出链表的结构!

c 复制代码
typedef int SLTDataType;
typedef struct SListNode
{
	//存储数据
	SLTDataType val;
	//存储下一块空间的地址
	struct SListNode* next;
}SListNode;

简单认识链表的物理结构!

一个区域存下一个区域的地址,一个区域存数据,这样就用地址把申请的空间链接起来了!

下面实现一下接口:
//申请节点
SListNode* BuySListNode(SLTDataType x);
//打印链表
void SListPrint(SListNode* phead);
//释放节点
void SListDestory(SListNode** pphead);
//尾插
void SListPushBack(SListNode** pphead,SLTDataType x);
//头插
void SListPushFront(SListNode** pphead,SLTDataType x);
//尾删
void SListPopBack(SListNode** pphead);
//头删
void SListPopFront(SListNode** pphead);
//查找节点
SListNode* FindSList(SListNode* phead,SLTDataType x);
//删除指定位置pos
void SListErase(SListNode** pphead,SListNode* pos)
//在pos节点之后插入
void SListInsertAfter(SListNode* pos,SLTDataType x)
//删除pos后面的一个节点
void SListEraseAfrer(SListNode* pos);

下面实现一下这个接口
//先大概写一下测试文件

c 复制代码
//Test.c -- 测试文件
#include "SList.h"


void SListTest()
{
	SListNode* phead = NULL;
	SListPushBack(&phead, 1);
	SListPushBack(&phead, 2);
	SListPushBack(&phead, 3);
	SListPushBack(&phead, 4);
	SListPrint(phead);
	//SListPushFront(&phead, 4);
	//SListPushFront(&phead, 3);
	//SListPushFront(&phead, 2);
	//SListPushFront(&phead, 1);
	//SListPrint(phead);
	//SListPopBack(&phead);
	//SListPopBack(&phead);
	//SListPopBack(&phead);
	//SListPopBack(&phead);
	//SListPrint(phead);
	//SListPopFront(&phead);
	//SListPopFront(&phead);
	//SListPopFront(&phead);
	//SListPopFront(&phead);
	//SListPrint(phead);
	SListNode* find = SListFind(phead,1);
	//SListErase(&phead, find);
	//SListPrint(phead);
	SListInsertAfter(find,11);
	SListPrint(phead);
	//SListEraseAfter(find);
	//SListPrint(phead);
}
int main()
{
	SListTest();
	return 0;
}

//尾插怎么写?
//1.考虑没有节点的情况
//2.考虑有节点的情况。直接插在尾巴后面

c 复制代码
void  SListPushBack(SListNode** pphead, SLTDataType  x)
{
	//二级指针不能传null
	assert(pphead);
	//申请节点
	SListNode* newnode = BuySListNode(x);
	//1.一个节点问题
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	//2.其它
	else {
		SListNode* cur = *pphead;
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
}

//头插怎么写?
//头插有点特殊,不用考虑任何情况,可以直接头插
//因为刚开始SListNode* plist = NULL;刚开始给的是NULL,NULL也是一个地址,所以,申请一个新的节点,可以直接存NULL。
//代码如下

c 复制代码
void SListPushFront(SListNode** pphead, SLTDataType  x)
{
	//二级指针不能传null
	assert(pphead);
	//申请节点
	SListNode* newnode = BuySListNode(x);
	newnode->next = (*pphead);
	*pphead = newnode;
}

//尾删怎么写?
//要考虑清楚一件事,要正常尾删,必须要能找到前一个节点。因此,考虑只有一个节点和其它节点两种情况!

c 复制代码
void  SListPopBack(SListNode** pphead)
{
	assert(pphead);
	//链表不能为NULL
	assert(*pphead);
	//1.1个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else{
		//2.至少2个节点问题
		SListNode* cur = *pphead;
		SListNode* prev = NULL;
		while (cur->next)
		{
			prev = cur;
			cur = cur->next;
		}
		//删除节点
		prev->next = NULL;
		free(cur);
		cur = NULL;
	}
}

//头删怎么写?
//要考虑头删怎么写,要删除头,把下一个节点存起来,当做newHead,即使下一个节点是NULL,也可以存起来,所以只有一种情况!

c 复制代码
void  SListPopFront(SListNode** pphead)
{
	assert(pphead);
	//检测是否有节点
	assert(*pphead);
	SListNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

//在pos节点之后插入,怎么写?
//可以把pos后面的先存起来,然后在pos之后插入
//或先把节点插在pos之后节点的前面,在把pos里面存新节点

c 复制代码
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	//assert(pos->next);
	if (pos->next == NULL)
	{
		printf("pos之后的节点为null\n");
		return;
	}
	SListNode* next = pos->next;
	SListNode* nnext = pos->next ->next;
	pos->next = nnext;
	free(next);
	next = NULL;
}

//怎样删除pos之后节点?
//1.检测pos之后是不是NULL节点
//2.保存pos后面的后面节点(NULL没有影响),删除pos之后的节点,在链接保存的节点

c 复制代码
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	//assert(pos->next);
	if (pos->next == NULL)
	{
		printf("pos之后的节点为null\n");
		return;
	}
	SListNode* next = pos->next;
	SListNode* nnext = pos->next ->next;
	pos->next = nnext;
	free(next);
	next = NULL;
}

//怎样删除pos节点?
//要删除pos节点,就要找前面和后面(后面的为NULL也可以),但是前面不能没有节点
//因此,考虑pos前面没有节点和有节点
//pos前面没有节点,pos是头,直接头删
//pos前面有节点,正常删除

c 复制代码
//删除指定位置
void SListErase(SListNode** pphead,SListNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);
	//考虑pos前面没有节点
	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	//其它
	else {
		SListNode* prev = *pphead;
		while (prev->next!=pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

//打印存储的数据
//直接遍历即可

c 复制代码
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur)
	{
		printf("->%d", cur->val);
		cur = cur->next;
	}
	printf("->NULL\n");
}

//把堆区申请的空间还给操作系统

c 复制代码
void SListDestory(SListNode** pphead)
{
	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

完整代码

c 复制代码
//SList.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>


typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType val;
	struct SListNode* next;
}SListNode;

SListNode* BuySListNode(SLTDataType x);
void SListPrint(SListNode* phead);
void  SListPushBack(SListNode** pphead, SLTDataType  x);
void SListPushFront(SListNode** pphead, SLTDataType  x);
void  SListPopBack(SListNode** pphead);
void  SListPopFront(SListNode** pphead);
SListNode* SListFind(SListNode* phead);
//删除指定指点位置
void SListErase(SListNode** pphead,SListNode* pos);
void SListInsertAfter(SListNode* pos, SLTDataType x);
void SListEraseAfter(SListNode* pos);
void SListDestory(SListNode** pphead);
c 复制代码
//sList.c
#include "SList.h"

SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("BuySListNode malloc fail!");
		return 1;
	}
	//申请成功
	newnode->next = NULL;
	newnode->val = x;
	return newnode;
}

void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur)
	{
		printf("->%d", cur->val);
		cur = cur->next;
	}
	printf("->NULL\n");
}
void  SListPushBack(SListNode** pphead, SLTDataType  x)
{
	//二级指针不能传null
	assert(pphead);
	//申请节点
	SListNode* newnode = BuySListNode(x);
	//1.一个节点问题
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	//2.其它
	else {
		SListNode* cur = *pphead;
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
}


void SListPushFront(SListNode** pphead, SLTDataType  x)
{
	//二级指针不能传null
	assert(pphead);
	//申请节点
	SListNode* newnode = BuySListNode(x);
	newnode->next = (*pphead);
	*pphead = newnode;
}


void  SListPopBack(SListNode** pphead)
{
	assert(pphead);
	//链表不能为NULL
	assert(*pphead);
	//1.1个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else{
		//2.至少2个节点问题
		SListNode* cur = *pphead;
		SListNode* prev = NULL;
		while (cur->next)
		{
			prev = cur;
			cur = cur->next;
		}
		//删除节点
		prev->next = NULL;
		free(cur);
		cur = NULL;
	}
}


void  SListPopFront(SListNode** pphead)
{
	assert(pphead);
	//检测是否有节点
	assert(*pphead);
	SListNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

SListNode* SListFind(SListNode* phead,SLTDataType x)
{
	//不能为NULL
	assert(phead);
	SListNode* cur = phead;
	while (cur)
	{
		if (cur->val == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	//找不到,为NULL
	return NULL;
}

void SListInsertAfter(SListNode* pos, SLTDataType x)
{
	assert(pos);
	//申请节点
	SListNode* newnode = BuySListNode(x);
	SListNode* next = pos->next;
	pos->next = newnode;
	newnode->next = next;
}

void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	//assert(pos->next);
	if (pos->next == NULL)
	{
		printf("pos之后的节点为null\n");
		return;
	}
	SListNode* next = pos->next;
	SListNode* nnext = pos->next ->next;
	pos->next = nnext;
	free(next);
	next = NULL;
}

//删除指定位置
void SListErase(SListNode** pphead,SListNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);
	//考虑pos前面没有节点
	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	//其它
	else {
		SListNode* prev = *pphead;
		while (prev->next!=pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

void SListDestory(SListNode** pphead)
{
	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}
c 复制代码
//测试代码
#include "SList.h"


void SListTest()
{
	SListNode* phead = NULL;
	SListPushBack(&phead, 1);
	SListPushBack(&phead, 2);
	SListPushBack(&phead, 3);
	SListPushBack(&phead, 4);
	SListPrint(phead);
	//SListPushFront(&phead, 4);
	//SListPushFront(&phead, 3);
	//SListPushFront(&phead, 2);
	//SListPushFront(&phead, 1);
	//SListPrint(phead);
	//SListPopBack(&phead);
	//SListPopBack(&phead);
	//SListPopBack(&phead);
	//SListPopBack(&phead);
	//SListPrint(phead);
	//SListPopFront(&phead);
	//SListPopFront(&phead);
	//SListPopFront(&phead);
	//SListPopFront(&phead);
	//SListPrint(phead);
	SListNode* find = SListFind(phead,1);
	//SListErase(&phead, find);
	//SListPrint(phead);
	SListInsertAfter(find,11);
	SListPrint(phead);
	//SListEraseAfter(find);
	//SListPrint(phead);
	SListDestory(&phead);
}
int main()
{
	SListTest();
	return 0;
}

完结!!!

相关推荐
Watink Cpper23 分钟前
[灵感源于算法] 算法问题的优雅解法
linux·开发语言·数据结构·c++·算法·leetcode
-qOVOp-27 分钟前
408第一季 - 数据结构 - 折半查找与二叉排序树
数据结构
এ᭄画画的北北2 小时前
力扣-35.搜索插入位置
数据结构·算法·leetcode
蓝澈11213 小时前
数据结构之常用排序算法(冒泡、选择等)
数据结构·算法·排序算法
Chenyu_3109 小时前
12.找到字符串中所有字母异位词
c语言·数据结构·算法·哈希算法
豪斯有话说13 小时前
C++_哈希表
数据结构·c++·散列表
记得早睡~14 小时前
leetcode73-矩阵置零
数据结构·leetcode·矩阵
a.30215 小时前
C++ 时间处理指南:深入剖析<ctime>库
数据结构·c++·算法
圈圈编码21 小时前
LeetCode Hot100刷题——合并两个有序链表
java·数据结构·算法·leetcode·链表
jingfeng5141 天前
详解快排的四种方式
数据结构·算法·排序算法