其他分享
首页 > 其他分享> > 单链表的各种花样

单链表的各种花样

作者:互联网

单链表的各种花样

以下的数据结构基于单链表

反转从m到n的链表(reverse pro版)

考虑几个问题
实现思路

举个例子,假设链表是1 -> 2 -> 3 -> 4 -> 5 ->6 ->7,m=3,n=5

首先,将头指针指向2(m-1)的位置,用一个指针p保存,再用一个指针q保存3(m)位置

然后,开始迭代处理3到5中间(也就是3 -> 4变成4 -> 3,4 -> 5变成5 ->4)

最后,把m-1的next指向n(接头),把n+1的next指向m(续尾)

void reverseBetween(int m, int n) {  //反转第n个到第m个元素
	if (m >= n || m < 0 || n < 0)
		return;

	Node* p = head;

	for (int i = 0; i < m - 1; ++i)  //移动p到m-1的位置
		p = p->next;

	Node* q = p->next;  //m位置

	Node* pre = p->next;
	Node* cur = pre->next;

	for (int i = 0; i < n - m; ++i) {  //处理第m到第n的节点中间
		Node* temp = cur->next;
		cur->next = pre;
		pre = cur;
		cur = temp;
	}
	p->next = pre;
	q->next = cur;
}
说明

当m > 1时,用p代替head移动到m-1,可以保持head原有位置,当m = 1时p就是head副本,p->next = pre使得head也被修改

当n等于链表长度时,cur从for循环出来时就是nullptr(就很优雅hahah)

有序列表删除重复元素

删除的时候临时变量保存中间节点

只有不重复的时候才node才向前移动

	void removeDuplicate() {
		Node* node = head;

		while (node->next->next)
		{
			Node* temp = node->next;
			if (node->next->elem == node->next->next->elem)
			{
				node->next = node->next->next;
				delete temp;
			}
			else
			node = node->next;
		}
	}

合并两个有序链表

思考几个问题

原链表是否需要保持不变?如果需要那么需要使用栈依次弹出两链表中较大者插入到新链表中。

若不需要,则可以将要合并的链表插入到合适的位置

	void mergeList(Node* n2) {  //头插法建立链表时

		Node* p = head;
		Node* q = n2->next;
		while (q) {
			{
				while (p->next && p->next->elem > q->elem)  //寻找合适位置
					p = p->next;
			}
			Node* temp = q;  //q加入到合适位置中
			q = q->next;  //合并链表向前
			temp->next = p->next;
			p->next = temp;
			++head->elem;  //记录链表元素个数
		}
	}

求链表的中间元素/倒数第k个元素

双指针法

求中间元素可以让两个指针步长差一倍,当快指针到达表尾,慢指针所指就是中间元素

(倒数第k个元素可以保持步长一致,但快指针先走k-1步)

Node* findMidElement() {
	if (head->elem <= 2)
		return head->next;
	else {
		Node* p = head->next;
		Node* q = head->next->next;
		while (q)
		{
			p = p->next;
			q = q->next->next;
		}
		return p;
	}
}

判断链表是否有环/求环的长度

双指针法

怎么理解有环的时候快慢指针一定会在慢指针一遍循环结束前相遇呢?就跟跑操场一样,跑得快的能在跑得慢的跑完一圈之前再次追上。(快的速度>=慢的速度*2)

	int circleLength() {
		if (head->elem <= 1)
			return 0;
		Node* slow = head->next;  //慢指针
		Node* fast = head->next->next;  //快指针

		while (fast && fast != slow)  //若fast指向表尾为nullptr则无环
		{
			slow = slow->next;
			fast = fast->next->next;
		}
		if (fast == nullptr)  //若不成立,则此时slow与fast处在交点位置
			return 0;
		int count = 1;  //这时候定住fast,slow跑一边环就得到长度了
		slow = slow->next;
		while (slow != fast)
		{
			slow = slow->next;
			++count;
		}
		return count;
	}

求两链表的第一个公共节点

链表不是二叉树,有公共节点意味着俩链表会汇聚,但绝不会分流。所以链表的样子是Y型,第一个公共节点及其之后全是公共节点

这样一来就好说了,前边我们在头节点保存了链表的长度,要理解在长链表长度是len1,短链表长度是len2时,在长链表的前len1-len2区间是不可能有公共节点的,理由在划下划线部分。

实现思路:
  1. 获取长度len1,len2
  2. 长链表向后移动len1-len2个位置
  3. 对齐之后开始检查对应位置是否指针相等,否则同步后移
  4. 处理边界条件,检查输入合法性

标签:Node,slow,head,各种,花样,next,链表,单链,指针
来源: https://www.cnblogs.com/kite97/p/13476602.html