561-单链表刷题(1)

在这里插入图片描述

单链表逆序(原地逆置)

在这里插入图片描述
单链表的逆序后的结果就是:当我们现在去访问单链表的头节点,然后访问的节点的顺序是:18,32,67,25

数据结构跟算法是永远离不开复杂度概念的
在这里插入图片描述
算法执行所耗费的时间,算法执行所占用的内存空间
复杂度越小越好,意味着性能越高,占用的内存空间越小,处理的速度越快。

在这里插入图片描述
我们要想到:头插法插出来的链表刚好和输入的是相反的
我们可以定义1个指针p指向第一个有效节点,
在这里插入图片描述
我们要把p前面的箭头去掉,这个头节点的next域不再记录第一个有效节点的地址,把头节点的next域置为空
在这里插入图片描述

现在这个head链表是空链表了,只剩下头节点了。
在这里插入图片描述

在这里插入图片描述
现在要做的是:把p指向的节点按头插法插入到上面的链表中
我们要先把67节点的地址记住,然后把25头插
在这里插入图片描述
在这里插入图片描述
然后把p指向q,q=q->next

在这里插入图片描述
然后把p指向的节点按照头插法插入上面的链表中
在这里插入图片描述
在这里插入图片描述
以此类推

//单链表逆序
void ReverseLink(Clink& link)
{
    Node* head = link.head_;
    Node* p = head->next_;
    if (p == nullptr)
    {
        return;
    }

    head->next_ = nullptr;

    while (p != nullptr)
    {
        Node* q = p->next_;

        //p指针指向的节点进行头插
        p->next_ = head->next_;
        head->next_ = p;

        p = q;
    }
}

单链表求倒数第k个节点

在这里插入图片描述
倒数第1个节点是18,倒数第2个节点是32,倒数第3个节点是67,倒数第4个节点是25

时间复杂度和空间复杂度越小越好
单链表是不可能从后向前遍历的,所以不能定义尾指针指向尾节点
那怎么办?
方法1:开辟一个数组,存放这些数据,然后访问到数组末尾位置,下标减减
这个操作浪费空间。
方法2:遍历链表,统计节点的个数。倒数几个,就是正数的:总个数-倒数的个数 然后从头节点开始遍历正数的个数访问就到了
但是假如这个链表有400万个节点,找倒数第3各个,岂不是要把所有节点遍历,然后再从头节点遍历(400万-3)个节点找到。总共把链表遍历了2遍,这个链表越长,我们花费的时间就越大。

方法3
双指针思想
定义一个指针pre指向头节点,定义一个指针p指向头节点
在这里插入图片描述
如果要找倒数第k个节点的话,先让p指向正数第k个节点
假设现在要找倒数第3个节点,k=3
让p指向正数第3个节点,也就是p走(k=3)次,pre不动
在这里插入图片描述
现在pre和p一起走,先一起走1步
在这里插入图片描述
p指向末尾节点,然后pre和p继续走
在这里插入图片描述

p为空了,我们看出,当p为空的时候,pre刚好指向倒数第k个节点了’

如果p和pre是初始化指向第一个有效节点,首先要判空p,然后p往后走(k-1)个节点,然后p和pre一起向后走,直到p->next为空,pre指向的就是倒数第k个节点
在这里插入图片描述
在这里插入图片描述

//求倒数第k个节点的值
bool GetLaskKNode(Clink& link, int k, int& val)
{
    Node* head = link.head_;
    Node* pre = head;
    Node* p = head;

    if (k < 1)
    {
        return false;
    }

    for (int i = 0; i < k; i++)
    {
        p = p->next_;
        if (p == nullptr)
        {
            return false;//正数第k个不存在,倒数第k个自然也不存在
        }
    }

    //此时pre在头节点,p在正数第k个节点,进入while循环
    while (p != nullptr)
    {
        pre = pre->next_;
        p = p->next_;
    }

    val = pre->data_;
    return true;
}

合并两个有序单链表

在这里插入图片描述
这2个单链表都是有序的,现在把这两个单链表按序合并在第一个单链表上,最终结果也是有序的,第2个单链表置为空链表就可以了
把2个链表根据有序的节点进行连接,连接好把整个长链表接在第一个链表的头节点之后。第2个单链表置为空链表就可以了

三指针思想
1个指针p遍历链表1的节点,1个指针q遍历链表2的节点,
因为合并的是两个单链表的有效节点,所以这2个指针访问两个链表的第一个有效节点就可以了。
在这里插入图片描述

在这里插入图片描述

因为是最后合并的链表挂在第一个链表的头节点后面。
head1指针不能挪动。
我们定义一个last指针指向目前连接好的末尾节点,初始化指向是在链表1的头节点
在这里插入图片描述
然后p和q指向节点的数据域进行比较,25大于13,就把q指针指向的节点挂在last的后面

在这里插入图片描述
然后q=q->next
然后last指针往后挪动一个位置

在这里插入图片描述
在这里插入图片描述
然后继续,p和q比较,又是q小,就继续做一样的事情
在这里插入图片描述
在这里插入图片描述
然后p和q比较,p比较小了,把p指向的节点连过来
在这里插入图片描述
在这里插入图片描述
然后p和q比较,p小,p指向的节点连进来
在这里插入图片描述
然后p和q比较,q小,把q指向的节点连进去
在这里插入图片描述
现在q指向空了,p和q不能比较了
所以,我们有一个while循环条件:
在这里插入图片描述
当两个链表,其中一个链表遍历到空了。
如果q先空了,就是刚才的情况。
在这里插入图片描述
这样就OK了!
在这里插入图片描述
在这里插入图片描述
如果是p先空了
在这里插入图片描述
这样就完成了!

//合并两个有序的单链表
void MergeLink(Clink& link1, Clink& link2)
{
    Node* p = link1.head_->next_;
    Node* q = link2.head_->next_;
    Node* last = link1.head_;
    link2.head_->next_ = nullptr;

    while (p != nullptr && q != nullptr)
    {
        if (p->data_ < q->data_)
        {
            last->next_ = p;
            p = p->next_;
            last = last->next_;
        }
        else
        {
            last->next_ = q;
            q = q->next_;
            last = last->next_;
        }
    }

    if (p != nullptr)
    {
        last->next_ = p;
    }
    else
    {
        last->next_ = q;
    }
}

总代码

#include<iostream>
#include<string.h>
#include<time.h>
using namespace std;

struct Node
{
	Node(int data = 0) :data_(data), next_(nullptr){}
	int data_;
	Node* next_;
};
class Clink
{
public:
	Clink()
	{
		head_ = new Node();
	}
	~Clink()
	{
		Node* p = head_;
		while (p != nullptr)
		{
			head_ = head_->next_;
			delete p;
			p = head_;
		}
		head_ = nullptr;
	}
public:
	void InsertTail(int val)
	{
		Node* p = head_;
		while (p->next_ != nullptr)
		{
			p = p->next_;
		}
		Node* node = new Node(val);
		p->next_ = node;
	}
	void InsertHead(int val)
	{
		Node* node = new Node(val);
		node->next_ = head_->next_;
		head_->next_ = node;
	}
	void Remove(int val)
	{
		Node* p = head_;
		Node* q = head_->next_;
		while (q != nullptr)
		{
			if (q->data_ == val)
			{
				p->next_ = q->next_;
				delete q;
				return;
			}
			else
			{
				p = q;
				q = q->next_;
			}
		}
	}
	void RemoveAll(int val)
	{
		Node* p = head_;
		Node* q = head_->next_;
		while (q != nullptr)
		{
			if (q->data_ == val)
			{
				p->next_ = q->next_;
				delete q;
				q = p->next_;
			}
			else
			{
				p = q;
				q = q->next_;
			}
		}
	}
	bool Find(int val)
	{
		Node* p = head_->next_;
		while (p != nullptr)
		{
			if (p->data_ == val)
			{
				return true;
			}
			else
			{
				p = p->next_;
			}
		}
		return false;
	}
	void show()
	{
		Node* p = head_->next_;
		while (p != nullptr)
		{
			cout << p->data_ << " ";
			p = p->next_;
		}
		cout << endl;
	}
	friend void ReverseLink(Clink& link);
	friend bool GetLastKNode(Clink& link, int k, int& val);
	friend void MergeLink(Clink& link1, Clink& link2);
private:
	Node* head_;
};

void ReverseLink(Clink& link)
{
	Node* head = link.head_;
	Node* p = head->next_;
	head->next_ = nullptr;
	if (p == nullptr)
	{
		return;
	}
	while (p != nullptr)
	{
		Node* q = p->next_;
		p->next_ = head->next_;
		head->next_ = p;
		p = q;
	}
}
bool GetLastKNode(Clink& link, int k, int& val)
{
	Node* head = link.head_;
	Node* pre = head;
	Node* p = head;
	if (k < 1)
	{
		return false;
	}
	for (int i = 0; i < k; ++i)
	{
		p = p->next_;
		if (p == nullptr)
		{
			return false;
		}
	}
	while (p != nullptr)
	{
		pre = pre->next_;
		p = p->next_;
	}
	val = pre->data_;
	return true;
}
void MergeLink(Clink& link1, Clink& link2)
{
	Node* p = link1.head_->next_;
	Node* q = link2.head_->next_;
	Node* last = link1.head_;
	link2.head_->next_ = nullptr;
	
	while (p != nullptr && q != nullptr)
	{
		if (p->data_ < q->data_)
		{
			last->next_ = p;
			p = p->next_;
			last = last->next_;
		}
		else
		{
			last->next_ = q;
			q = q->next_;
			last = last->next_;
		}
	}
	if (p != nullptr)
	{
		last->next_ = p;
	}
	else
	{
		last->next_ = q;
	}
}
int main()
{
	Clink link;
	for (int i = 0; i < 10; ++i)
	{
		link.InsertTail(rand() % 100);
	}
	link.show();
	int val;
	int k = 110;
	if (GetLastKNode(link, k, val))
	{
		cout << val << endl;
	}
	else
	{
		cout << "不存在" << endl;
	}

	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林林林ZEYU

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

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

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

打赏作者

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

抵扣说明:

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

余额充值