C++手撕单链表

本文介绍了如何用C++定义一个单向链表,包括默认和有参构造函数。接着讨论了尾插、头插函数的实现,特别是处理空链表的情况。此外,还涵盖了删除指定值结点、按下标删除结点以及升序排序链表的方法。所有操作都考虑了边界条件和数据安全。
摘要由CSDN通过智能技术生成

        对于数据结构的学习,亲手敲一遍还是很有必要的,一动手才能发现自己的知识还是存在很多的漏洞。由于是第一次写,可能存在些错误(我自己测试的时候是没发现问题的),欢迎评论区指正。

下面用C++来定义一个简单的单向链表,再写下默认构造和有参构造。

struct node
{
	int val;
	node* next;

	node() = default;//默认构造

	node(int val, node* next = nullptr)
		: val(val), next(next) {}
};

写一个尾插函数,传入链表头结点,并给插入的新结点赋值key,这里不要忘记处理空链表的情况。注意!由于这里我是直接用head去遍历链表,所以参数是以形参的形式传入,不能以引用的形式传参(node*& head),不然head的值和指向会被改变。如果是引用传参,需要定义一个临时结点temp指向头节点(见下文),再通过temp去遍历

void end_insert(node* head,int key)
{
	if (head == nullptr)
	{// 处理空链表的情况
		cout << "头结点为空!" << endl;
		return;
	}

	node* new_node = new node(key);

	while (head->next)//遍历
	{
		head = head->next;
	}

	head->next = new_node;
}

这里我给上个尾插函数做了些优化,如果是空链表,那么我们就直接给头指针插值,这里需要使用引用传参,因为直接改变了参数head本身

void end_insert(node*& head,int key)
{
	if (head == nullptr)
	{// 处理空链表的情况
		head = new node(key);
		return;
	}

	node* new_node = new node(key);

	node* temp = head;
	while (temp->next)//遍历
	{
		temp = temp->next;
	}

	temp->next = new_node;
}

再写一个头插

void begin_insert(node*& head, int val)
{
	node* new_node = new node(val);
	new_node->next = head;
	head = new_node;
}

遍历链表的函数依然不能忘记处理空链表的情况,加个const修饰保证数据安全性

void visit_node(const node* head)
{
	if (head == nullptr)
	{
		cout << "头结点为空" << endl;
		return;
	}

	const node* temp = head;
	int i = 1;

	while (temp)
	{
		cout << "node[ " << i++ << " ] = " << temp->val << endl;
		temp = temp->next;
	}
}

查找值为指定值val的结点,并删除,一样要使用引用传参,不过这里只能删除第一个值为val的结点

void val_erase(node*& head,int val)
{
	if (head == nullptr) // 检查头结点是否为空
	{
		cout << "未找到值相匹配的结点" << endl;
		return;
	}
	else if (head->next == nullptr)//只有一个头结点
	{
		if (head->val == val)//头结点就是目标结点
		{
			delete head;
			head = nullptr;
			cout << "结点已删除!" << endl;
			return;
		}
	}

	node* temp = head;//临时结点
	while (temp->next)
	{
		if (temp->next->val == val)//找到
		{
			node* dest = temp->next;//存储被删除的结点
			temp->next = temp->next->next;//指向被删除结点的下一个结点
			delete dest;//删除目标结点
			dest = nullptr;
			cout << "结点已删除!" << endl;
			return;
		}
		temp = temp->next;//向后遍历
	}

	cout << "未找到值相匹配的结点" << endl;
}

根据下标index删除指定结点,下标从0开始。这里依然要把麻烦的头指针单独拿出来写,遍历的时候,要使temp指向被删除结点的前一个结点,好进行删除后的链表拼接。如果下标为1,是不会进入for循环的,因此在for循环后面需要一个if去判定第二个结点是否为空。

void index_erase(node*& head, int index)
{
	node* temp = head;

	if (index == 0)//删除头结点
	{
		head = head->next;//新头结点
		delete temp;
		temp = nullptr;
		cout << "结点已删除!" << endl;
		return;
	}

	for (int i = 0; i < index-1; i++)//指向目标结点前一个位置
	{
		if (temp == nullptr)//防止index大于链表结点数
		{
			cout << "下标不合法,删除失败" << endl;
			return;
		}

		temp = temp->next;
	}

	if (temp->next == nullptr)
	{
		cout << "下标不合法,删除失败" << endl;
		return;
	}

	node* dest = temp->next;//存储被删除的结点
	temp->next = temp->next->next;//指向被删除结点的下一个结点
	delete dest;//删除目标结点
	dest = nullptr;
	cout << "结点已删除!" << endl;
}

查询值为val的结点,并返回这个结点,打印出下标

node* find_node(node* head, int val)
{
	int index = 0;
	while (head)
	{
		if (head->val == val)
		{
			cout << "目标结点下标为: " << index << endl;
			return head;
		}
		head = head->next;
		index++;
	}
	cout << "未找到该节点" << endl;
	return nullptr;
}

销毁链表,这里由于要让头指针head指向空,所以要以引用的形式传入

void destroy_node(node*& head)
{
	node* temp;
	while (head)
	{
		cout << "key = " << head->val << " 已销毁" << endl;
		temp = head->next;
		delete head;
		head = temp;
	}
	head = nullptr;
}

最后写一个升序排序的函数,这个排序是根据val的值重排链表的所有结点,而不是简单的给结点的val值进行排序

void sortedInsert(node*& head, node* new_node);

//升序排序
void sort_node(node*& head)
{
	// 空链表或只有一个元素,无需排序
	if (head == nullptr || head->next == nullptr) 
		return; 

	node* sorted{}, * next{};
	node* current = head;
	while (current)
	{
		next = current->next;
		sortedInsert(sorted, current);
		current = next;
	}
	head = sorted;
}

void sortedInsert(node*& head, node* new_node)
{
	if (head == nullptr || head->val >= new_node->val)//第一个值大
	{
		new_node->next = head;
		head = new_node;
	}
	else//第二个值大
	{
		node* current = head;
		while (current->next != nullptr && current->next->val < new_node->val)
		{
			current = current->next;
		}
		new_node->next = current->next;
		current->next = new_node;
	}
}

还有些头删尾删的函数比较简单,就不写了。如有错误,欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

头发乌黑茂密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值