数据结构——不带头节点的单链表

作者:小琛
欢迎转载,请标明出处

单链表的概念

概念:链表是一种物理存储结构上非连续、非顺序,逻辑上连续的结构是通过链表中的指针链 接次序实现的。如下图:
在这里插入图片描述
也就是说,我们的链表逻辑是借助结构体实现的,结构体允许成员包括自调用指针,因此我们定义的结构体内容包括两个:date即数据,自调用指针

单链表的实现

单链表的实现方式很多,这里鉴于后续的面试和oj题目类型,实现不带头节点、二级指针写法的单链表
手写单链表的主要目的还是了解清楚其逻辑,因此本博文实现了几个基本的功能
Plist.h

#ifndef _LIST_H__
#define _LIST_H__
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int DateType;

typedef struct PlistNode
{
	DateType _date;
	struct PlistNode* _next;
}PlistNode;

PlistNode* GetNode(DateType x);
void PushBack(PlistNode** pplist, DateType x);
void PopBack(PlistNode** pplist);
void PushFront(PlistNode** pplist, DateType x);
void PopFront(PlistNode** pplist);
PlistNode* ListFind(PlistNode* plist, DateType x);
void ListInsertAfter(PlistNode** pos, DateType x);
void SListEraseAfter(PlistNode** pos);
void Print(PlistNode* plist);

#endif

Plist.c

#include "List.h"
/*
函数功能:得到一个新的节点,并将要插入得值赋给该节点
入口参数:要插入得值
返回值:新节点的指针
*/
PlistNode* GetNode(DateType x)
{
	PlistNode* NewNode = (PlistNode*)malloc(sizeof(PlistNode));
	NewNode->_date = x;
	NewNode->_next = NULL;
	return NewNode;
}
/*
函数功能:尾插法
入口参数:某链表的头的地址,要插入的值
返回值:无
*/
void PushBack(PlistNode** pplist, DateType x)
{
	PlistNode* NewNode = GetNode(x);
	if (*pplist == NULL)
	{
		*pplist = NewNode;
	}
	else
	{
		PlistNode* tail = *pplist;
		while (tail->_next != NULL)
		{
			tail = tail->_next;
		}
		tail->_next = NewNode;
	}

}
/*
函数功能:尾删法
入口参数:某链表的头的地址
返回值:无
*/
void PopBack(PlistNode** pplist)
{
	//两情况:只有一个或零个数据、多个数据
	if (*pplist == NULL || (*pplist)->_next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		PlistNode* cur = *pplist;
		PlistNode* prv = NULL;
		while (cur->_next)
		{
			prv = cur;
			cur = cur->_next;
		}
		free(cur);
		cur = NULL;
		prv->_next = NULL;
	}
}
/*
函数功能:头插法
入口参数:某链表的头的地址,要插入的值
返回值:无
*/
void PushFront(PlistNode** pplist, DateType x)
{
	PlistNode* NewNode = GetNode(x);
	if (*pplist == NULL)
	{
		*pplist = NewNode;
	}
	else
	{
		NewNode->_next = *pplist;
		*pplist = NewNode;
	}
}
/*
函数功能:头插法
入口参数:某链表的头的地址
返回值:无
*/
void PopFront(PlistNode** pplist)
{
	//无、一个、多个
	if (*pplist == NULL)
	{
		return;
	}
	else if ((*pplist)->_next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		PlistNode* cur = (*pplist)->_next;
		free(*pplist);
		*pplist = cur;
	}
}
/*
函数功能:查找函数
入口参数:某链表的头的地址,要查找的值
返回值:无
*/
PlistNode* ListFind(PlistNode* plist, DateType x)
{
	assert(plist);
	PlistNode* cur = plist;
	while (cur != NULL)
	{
		if (x == cur->_date)
		{
			return cur;
		}
		cur = cur->_next;
	}
	return NULL;
}
/*
函数功能:在一个链表的pos位后插入
入口参数:一个链表的某一个节点,要插入的值
返回值:无
*/
void ListInsertAfter(PlistNode** pos, DateType x)
{
	PlistNode* cur = GetNode(x); 
	PlistNode* tmp = NULL;
	tmp = (*pos)->_next;
	(*pos)->_next = cur;
	cur->_next = tmp;
}
/*
函数功能:删除某个链表pos后的一个节点
入口参数:一个链表的某个节点
返回值:无
*/
void SListEraseAfter(PlistNode** pos)
{
	PlistNode* tmp = NULL;
	PlistNode* cur = NULL;
	tmp = (*pos)->_next;
	cur = tmp->_next;
	(*pos)->_next = cur;
	free(tmp);
	tmp = NULL;
}/*
函数功能:打印函数
入口参数:某链表的头的地址
返回值:无
*/
void Print(PlistNode* plist)
{
	PlistNode* cur = plist;
	while (cur != NULL)
	{
		printf("%d\n", cur->_date);
		cur = cur->_next;
	}
	printf("\n");
}


text.c

#include "List.h"

void text1()
{
	PlistNode* head = NULL;
	PlistNode* cur = NULL;
	PushBack(&head, 1);
	PushBack(&head, 2);
	PushBack(&head, 3);
	PushBack(&head, 4);
	PushBack(&head, 5);
	Print(head);
	PopBack(&head);
	Print(head);
	PushFront(&head, 0);
	Print(head);
	cur=ListFind(head, 4);
	Print(cur);
	ListInsertAfter(&cur, 100);
	Print(head);
	SListEraseAfter(&cur);
	Print(head);
}
void text2()
{
	PlistNode* head1 = NULL;
	PushFront(&head1, 0);
	PushFront(&head1, 1);
	PushFront(&head1, 2);
	Print(head1);
	PopFront(&head1);
	Print(head1);
	PopFront(&head1);
	Print(head1);
	PopFront(&head1);
	Print(head1);

}
int main()
{
	text1();
	//text2();
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值