数据结构——单向带头非循环链表的C语言代码实现

系列文章目录

数据结构——顺序表的C语言代码实现
数据结构——八种链表的C语言代码实现
数据结构——栈的C语言代码实现



前言

该篇文章是剩余六个链表之一的c语言代码实现,因为前两篇(单向不带头非循环与双向带头循环)中已经介绍过了链表中常见的接口函数和基础知识,故该篇文章只放代码,难点请看注释

一、List.h

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef int ListDataType;
typedef struct ListNode
{
	ListDataType data;
	struct ListNode* next;
}LN;
//初始化头结点
void ListInit(LN** phead);
//尾插法
void ListPushBack(LN* phead, ListDataType x);
//尾删法
void ListPopBack(LN* phead);
//头插法
void ListPushFront(LN* phead, ListDataType x);
//头删法
void ListPopFront(LN* phead);
//查找节点
LN* ListFind(LN* phead, ListDataType x);
//在指定节点前插入
void ListInsertFront(LN* phead, ListDataType x, ListDataType num);
//在指定节点后插入
void ListInsertBack(LN* phead, ListDataType x, ListDataType num);
//删除节点
void ListDeleteNode(LN* phead, ListDataType x);
//改变节点
void ListChangeNode(LN* phead, ListDataType x, ListDataType num);
//删除链表
void ListFree(LN* phead);
//打印链表
void ListPrint(LN* phead);

二、List.c

代码如下:

#include"List.h"
//定义全局的尾指针,便于接口函数实现
//注意该指针必须在这个文件里定义
LN* tail = NULL;
//初始化头结点
void ListInit(LN** phead)
{
	*phead = (LN*)malloc(sizeof(LN));
	tail = *phead;
}
//尾插法
void ListPushBack(LN* phead, ListDataType x)
{
	if (phead->next == NULL)
	{
		printf("error\n");
		return;
	}
	LN* tem = (LN*)malloc(sizeof(LN));
	tem->data = x;
	tem->next = NULL;
	tail->next = tem;
	tail = tem;
}
//尾删法
void ListPopBack(LN* phead)
{
	if (phead->next == NULL)
	{
		printf("error\n");
		return;
	}
	LN* tem = phead;
	while (tem->next->next != NULL)
	{
		tem = tem->next;
	}
	free(tail);
	tem->next = NULL;
	tail = tem;
}
//头插法
void ListPushFront(LN* phead, ListDataType x)
{
	LN* tem = (LN*)malloc(sizeof(LN));
	tem->data = x;
	tem->next = phead->next;
	phead->next = tem;
}
//头删法
void ListPopFront(LN* phead)
{

	LN* tem = phead->next->next;
	free(phead->next);
	phead->next = tem;
}
//查找节点
LN* ListFind(LN* phead, ListDataType x)
{
	LN* tem = phead->next;
	while (tem)
	{
		if (tem->data == x)
		{
			return tem;
		}
		tem = tem->next;
	}
	return NULL;
}
//在指定节点前插入
void ListInsertFront(LN* phead, ListDataType x, ListDataType num)
{
	LN* tem = ListFind(phead, x);
	if (tem == NULL)
	{
		printf("链表中没有%d\n", x);
		return 0;
	}
	else
	{
		LN* insert = (LN*)malloc(sizeof(LN));
		insert->data = num;
		LN* preinsert = phead;
		while (preinsert->next != tem)
		{
			preinsert = preinsert->next;
		}
		insert->next = tem;
		preinsert->next = insert;
	}
}
//在指定节点后插入
void ListInsertBack(LN* phead, ListDataType x, ListDataType num)
{
	LN* tem = ListFind(phead, x);
	if (tem == NULL)
	{
		printf("链表中没有%d\n", x);
		return 0;
	}
	else
	{
		LN* insert = (LN*)malloc(sizeof(LN));
		insert->data = num;
		if (tem != tail)
		{
			insert->next = tem->next;
			tem->next = insert;
		}
		//注意此时需要判断所要插入的位置是否是尾节点
		//因为此时可能会设计tail的更改,而且print函数的循环条件与tail的值有关
		//如果要插入到尾指针之后,却只是使用
		//insert->next = tem->next;
		//tem->next = insert;
		//会造成tail指向倒数第二个节点,而不是尾节点
		else
		{
			tail->next = insert;
			tail = insert;
		}
	}
}
//删除节点
void ListDeleteNode(LN* phead, ListDataType x)
{
	LN* tem = ListFind(phead, x);
	if (tem == NULL)
	{
		printf("链表中没有%d\n", x);
		return 0;
	}
	else
	{
		if (tem == tail)
		{
			LN* pretail = phead;
			while (pretail->next != tail)
			{
				pretail = pretail ->next;
			}
			free(tail);
			pretail->next = NULL;
			tail = pretail;
		}
		else
		{
			LN* pretem = phead;
			while (pretem->next != tem)
			{
				pretem = pretem->next;
			}
			pretem->next = tem->next;
			free(tem);
		}
	}
}
//改变节点
void ListChangeNode(LN* phead, ListDataType x, ListDataType num)
{
	LN* tem = ListFind(phead, x);
	if (tem == NULL)
	{
		printf("链表中没有%d\n", x);
		return 0;
	}
	else
	{
		tem->data = num;
	}
}
//删除链表
void ListFree(LN* phead)
{
	LN* tem = phead;
	while (tem)
	{
		LN* next = tem->next;
		free(tem);
		tem = next;
	}
}
//打印链表
void ListPrint(LN* phead)
{
	LN* tem = phead->next;
	while (tem != tail->next)
	{
		printf("%d->", tem->data);
		tem = tem->next;
	}
	printf("NULL\n");
}


三、test.c

代码如下:

#include"List.h"
int main()
{
	LN* plist = NULL;
	ListInit(&plist);
	ListPushBack(plist, 1);
	ListPushBack(plist, 2);
	ListPushBack(plist, 3);
	ListPushFront(plist, 4);
	ListPushFront(plist, 4);
	ListPushFront(plist, 4);

	ListPrint(plist);
	ListPopFront(plist);
	ListPrint(plist);
	ListPopBack(plist);
	ListPrint(plist);
	/*LN* tem=ListFind(plist, 4);
	printf("%d %p", tem->data, tem);*/
	ListInsertFront(plist, 2, 6);
	ListPrint(plist);
	ListInsertBack(plist, 2, 6);
	ListPrint(plist);
	ListDeleteNode(plist, 2);
	ListPrint(plist);
	ListChangeNode(plist, 4, 10);
	ListPushBack(plist, 12);
	ListPrint(plist);
	ListChangeNode(plist, 12, 13);
	ListPrint(plist);
	ListDeleteNode(plist, 13);
	ListPrint(plist);
	ListFree(plist);
	return 0;
}

总结

相信大家在认真实现最简单和最复杂的两种链表之后,便练就了闭眼敲链表的无上神功!
但学习贵在坚持,剩余六种链表的实现过程略感无趣,却依然要坚持全部手敲。加油!

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值