链表系列

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk_bjut_edu_cn/article/details/83583103

剑指Offer(6)--从尾到头打印链表 

#include<stack>
#include<iostream>
using namespace std;
struct ListNode
{
	int m_value;
	ListNode *m_next;
};
//用stack实现的,而递归本质上就是一个栈结构,所以也可以用递归来实现
void printListReversing_1(ListNode *node)
{
	stack<ListNode*> sList;
	while (node != nullptr)
	{
		sList.push(node);
		node = node->m_next;
	}
	while (!sList.empty())
	{
		cout << sList.top()->m_value << "	";
		sList.pop();
	}
}
//用递归的方式实现
void printListReversing_2(ListNode *node)
{
	if (node != nullptr)
	{
		if (node->m_next != nullptr)
			printListReversing_2(node->m_next);
		cout << node->m_value << "	";
	}
}

剑指Offer(22)--链表中倒数第k个节点

#include<iostream>
using namespace std;
struct ListNode
{
	int m_value;
	ListNode *m_next;
};
/*
输入一个链表,输出该链表中倒数第k个节点
*/
//分成两个指针走,使它俩的距离相差k-1
int printListNode(ListNode *node, int k)
{
	if (node == nullptr || k <= 0)
		return -1;
	ListNode *firstNode = node;
	ListNode *secondNode = node;
	for (int i = 0; i < k-1; ++i)
	{
		if (firstNode->m_next == nullptr)
		{
			cout << "链表个数小于k" << endl;
			return -1;
		}
		firstNode = firstNode->m_next;
	}
	while (firstNode->m_next != nullptr)
	{
		firstNode = firstNode->m_next;
		secondNode = secondNode->m_next;
	}
	return secondNode->m_value;
}
int main(void)
{
	ListNode *m_node1 = new ListNode();
	ListNode *m_node2 = new ListNode();
	ListNode *m_node3 = new ListNode();
	ListNode *m_node4 = new ListNode();
	m_node1->m_value = 1;
	m_node1->m_next = m_node2;
	m_node2->m_value = 2;
	m_node2->m_next = m_node3;
	m_node3->m_value = 3;
	m_node3->m_next = m_node4;
	m_node4->m_value = 4;
	m_node4->m_next = nullptr;
	int result = printListNode(m_node1,5);
	cout << result;
	system("pause");
	return 0;
}

 剑指Offer(24)--反转链表

#include<iostream>
using namespace std;
struct ListNode
{
	int m_value;
	ListNode *m_next;
};
/*
用三个指针解决问题
*/
ListNode *reverseList(ListNode *node)
{
	if (node == nullptr || node->m_next == nullptr)
		return nullptr;
	ListNode *preNode = node;
	ListNode *currentNode = node->m_next;
	ListNode *nextNode = nullptr;
	preNode->m_next = nullptr;
	while (currentNode != nullptr)
	{
		nextNode = currentNode->m_next;
		currentNode->m_next = preNode;
		preNode = currentNode;
		currentNode = nextNode;
	}
	return preNode;
}
void printListValue(ListNode *node)
{
	while (node != nullptr)
	{
		cout << node->m_value << " ";
		node = node->m_next;
	}
	cout << endl;
}
int main(void)
{
	ListNode *m_node1 = new ListNode();
	ListNode *m_node2 = new ListNode();
	ListNode *m_node3 = new ListNode();
	ListNode *m_node4 = new ListNode();
	ListNode *m_node5 = new ListNode();
	m_node1->m_value = 1;
	m_node1->m_next = m_node2;
	m_node2->m_value = 2;
	m_node2->m_next = m_node3;
	m_node3->m_value = 3;
	m_node3->m_next = m_node4;
	m_node4->m_value = 4;
	m_node4->m_next = nullptr;
	m_node5 = reverseList(m_node1);
	printListValue(m_node5);
	system("pause");
	return 0;
}

 剑指Offer(25)--合并两个排序的链表

比如是两个递增排序的链表

#include<iostream>
using namespace std;
struct ListNode
{
	int m_value;
	ListNode *m_next;
};
//递归版本
ListNode *mergeList(ListNode *node1, ListNode *node2)
{
	if (node1 == nullptr)
		return node2;
	else if (node2 == nullptr)
		return node1;
	ListNode *mergeHead = nullptr;
	if (node1->m_value < node2->m_value)
	{
		mergeHead = node1;
		mergeHead->m_next = mergeList(node1->m_next, node2);
	}
	else
	{
		mergeHead = node2;
		mergeHead->m_next = mergeList(node1, node2->m_next);
	}
	return mergeHead;
}

 剑指Offer(35)--复杂链表的复制

在复杂链表中,每个节点除了有一个m_next指针指向下一个节点,还有一个m_rand指针指向链表中的任意节点或者nullptr。

#include<iostream>
#include<map>
using namespace std;
struct ListNode
{
	int m_value;
	ListNode *m_next;
	ListNode *m_rand;
};
/*
方法一:两个链表是通过map串起来的,原始的链表
节点作为键,copy的链表作为值,然后根据键的->next
和->rand,找值的->next和->rand
*/
ListNode *copyListWithRand1(ListNode *head)
{
	map<ListNode*, ListNode*> m;
	ListNode *curNode = head;
	//先构造出待复制的全部结点
	while (curNode != nullptr)
	{
		ListNode *copyNode = new ListNode();
		copyNode->m_value = curNode->m_value;
		m.insert(pair<ListNode*, ListNode*>(curNode, copyNode));
		curNode = curNode->m_next;
	}
	curNode = head;
	//将map中的复制过来的结点串联起来
	while (curNode!= nullptr)
	{
		m.find(curNode)->second->m_next = m.find(curNode)->first->m_next;
		m.find(curNode)->second->m_rand = m.find(curNode)->first->m_rand;
		curNode = curNode->m_next;
	}
	return m.find(head)->second;
}

/*
方法二:不使用哈希表,利用的是在原来的
链表上插入copy的节点,找到rand之后再分开
*/
ListNode *copyListWithRand2(ListNode *head)
{
	if (head == nullptr)
		return nullptr;
	ListNode *curNode = nullptr;
	ListNode *nextNode = nullptr;
	/*
	比如原来是2->1->8,现在就是构成
	2->2~->1->1~->8->8~,这就实现了不使用额外数据结构,
	而只是使用有限个变量
	*/
	while (curNode != nullptr)
	{
		nextNode = curNode->m_next;
		ListNode *copyNode = new ListNode();
		copyNode->m_value = curNode->m_value;
		curNode->m_next = copyNode;
		copyNode->m_next = nextNode;
		curNode = nextNode;
	}
	curNode = head;
	ListNode *copyNode = nullptr;
	/*
	下面做的是找rand,如果2->rand=8,那么2~->rand=8~;
	*/
	while (curNode != nullptr)
	{
		//cur! = nullptr,那么cur->next必然不为nullptr,因为经过了上面的复制操作
		nextNode = curNode->m_next->m_next;
		copyNode = curNode->m_next;
		copyNode->m_rand = curNode->m_rand != nullptr ? curNode->m_rand->m_next : nullptr;
		curNode = nextNode;
	}
	curNode = head;
	ListNode *resultHead = head->m_next;
	/*
	经过上面的步骤,就找到了2~、1~、8~->rand,但是现在的copy链表
	和原链表是在一起2->2~->1->1~->8->8~,下面进行分割
	*/
	while (curNode != nullptr)
	{
		//cur!=nullptr,那么cur->next必然不为nullptr,因为经过了上面的复制操作
		nextNode = curNode->m_next->m_next;
		copyNode = curNode->m_next;
		curNode->m_next = nextNode;
		copyNode->m_next = nextNode != nullptr ? nextNode->m_next : nullptr;
		curNode = nextNode;
	}
	return resultHead;
}

剑指Offer(23)--链表中环的入口节点

#include<iostream>
using namespace std;
struct ListNode
{
	int m_value;
	ListNode *m_next;
};
/*
判断单链表是否有环,如果有环,返回第一个入环的节点;
如果无环,返回NULL
准备两个指针,一个是快指针,一个是慢指针;快指针一次
走两步,慢指针一次走一步。如果快指针在走的过程中遇到
NULL,直接返回无环;如果有环,快指针和慢指针一定会在
环上相遇。相遇的时候快指针回到开始处,然后快指针由一次
走两步变为一次走一步,然后快慢指针一起走,相遇的节点
即为入环的节点。
*/
ListNode *getLoopListNode(ListNode *head)
{
	if (head == NULL || head->m_next == NULL || head->m_next->m_next == NULL)
		return NULL;
	ListNode *n1 = head->m_next;//慢指针
	ListNode *n2 = head->m_next->m_next;//快指针
	while (n1 != n2)
	{
		if (n2->m_next == NULL || n2->m_next->m_next == NULL)
			return NULL;
		n1 = n1->m_next;
		n2 = n2->m_next->m_next;
	}
	n2 = head;//将n2重新指向头节点
	while (n1 != n2)
	{
		n1 = n1->m_next;
		n2 = n2->m_next;
	}
	return n1;
}

剑指Offer(52)--两个链表的第一个公共节点

需要考虑链表是否有环,可以问面试者

#include<iostream>
using namespace std;
/*
两个单链表相交的一系列问题
【题目】 在本题中,单链表可能有环,也可能无环。给定两个
单链表的头节点 head1和head2,这两个链表可能相交,也可能
不相交。请实现一个函数, 如果两个链表相交,请返回相交的
第一个节点;如果不相交,返回null 即可。 要求:如果链表1
的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外
空间复杂度请达到O(1)。
*/
struct ListNode
{
	int m_value;
	ListNode *m_next;
};
/*
判断单链表是否有环,如果有环,返回第一个入环的节点;
如果无环,返回NULL
准备两个指针,一个是快指针,一个是慢指针;快指针一次
走两步,慢指针一次走一步。如果快指针在走的过程中遇到
NULL,直接返回无环;如果有环,快指针和慢指针一定会在
环上相遇。相遇的时候快指针回到开始处,然后快指针由一次
走两步变为一次走一步,然后快慢指针一起走,相遇的节点
即为入环的节点。
*/
ListNode *getLoopListNode(ListNode *head)
{
	if (head == NULL || head->m_next == NULL || head->m_next->m_next == NULL)
		return NULL;
	ListNode *n1 = head->m_next;//慢指针
	ListNode *n2 = head->m_next->m_next;//快指针
	while (n1 != n2)
	{
		if (n2->m_next == NULL || n2->m_next->m_next == NULL)
			return NULL;
		n1 = n1->m_next;
		n2 = n2->m_next->m_next;
	}
	n2 = head;//将n2重新指向头节点
	while (n1 != n2)
	{
		n1 = n1->m_next;
		n2 = n2->m_next;
	}
	return n1;
}
/*
如果loop1(入环节点)为NULL并且loop2也为NULL,
说明两个链表均无环。
下面的函数是在两个链表均无环找到第一个相交的节点
首先统计链表1和链表2的长度,并且拿到它们的末节点
得到长度len1和指针end1,长度len2和指针end2,先判断
end1是否等于end2(这里的相等是指内存地址,说明是
同一个节点,而不是指值),如果相等说明相加,反之,
不相交。如果end1等于end2,说明相加,但这个节点未必
是第一个相交的节点,要找第一个相交的节点,应该是len长
的那个链表先走距离差值的节点数,然后一起走,遇到相等的
节点即为第一个相交节点
*/
ListNode *noLoop(ListNode *head1, ListNode *head2)
{
	if (head1 == NULL || head2 == NULL)
		return NULL;
	ListNode *cur1 = head1;
	ListNode *cur2 = head2;
	int n1 = 1, n2 = 1;
	while (cur1->m_next != NULL)
	{
		++n1;
		cur1 = cur1->m_next;
	}
	while (cur2->m_next != NULL)
	{
		++n2;
		cur2 = cur2->m_next;
	}
	if (cur1 != cur2)
		return NULL;
	int n = n1 - n2;
	cur1 = head1;
	cur2 = head2;
	while (n > 0)
	{
		cur1 = cur1->m_next;
		--n;
	}
	while (n < 0)
	{
		cur2 = cur2->m_next;
		++n;
	}
	//cout << n << endl;
	while (cur1 != cur2)
	{
		cur1 = cur1->m_next;
		cur2 = cur2->m_next;
	}
	return cur1;
}
/*
如果一个链表有环,一个链表无环,结论是不可能相交
*/
/*
如果是两个有环链表,有三种情况
1.各自环各自的,不相交
2.先相交,然后共享同一个环
3.\    /,长得和天线宝宝一样
	\ /
	 O

如果loop1==loop2就是上面的第二种结构,如果loop1!=loop2,
则有1、3两种情况,此时从loop1开始继续走,直到又绕回
loop1还没有loop2这样一个节点,那就是情况1,否则就是情况3
*/
ListNode *bothLoop(ListNode *head1, ListNode *loop1, ListNode *head2, ListNode *loop2)
{
	ListNode *cur1 = NULL;
	ListNode *cur2 = NULL;
	//先各走的,然后一起环一个
	if (loop1 == loop2)
	{
		cur1 = head1;
		cur2 = head2;
		int n1 = 0, n2 = 0;
		while (cur1 != loop1)
		{
			++n1;
			cur1 = cur1->m_next;
		}
		while (cur2 != loop2)
		{
			++n2;
			cur2 = cur2->m_next;
		}
		int n = n1 - n2;
		cur1 = head1;
		cur2 = head2;
		while (n > 0)
		{
			cur1 = cur1->m_next;
			--n;
		}
		while (n < 0)
		{
			cur2 = cur2->m_next;
			++n;
		}
		while (cur1 != cur2)
		{
			cur1 = cur1->m_next;
			cur2 = cur2->m_next;
		}
		return cur1;
	}
	else
	{
		cur1 = loop1->m_next;
		while (cur1 != loop1)
		{
			if (cur1 == loop2)
				return loop1;
			cur1 = cur1->m_next;
		}
		//走到这说明是第一种情况,不相交
		return NULL;
	}
}
//接口函数
ListNode *getIntersectListNode(ListNode *head1, ListNode *head2)
{
	if (head1 == NULL || head2 == NULL) {
		return NULL;
	}
	ListNode *loop1 = getLoopListNode(head1);
	ListNode *loop2 = getLoopListNode(head2);
	if (loop1 == NULL && loop2 == NULL) {
		return noLoop(head1, head2);
	}
	if (loop1 != NULL && loop2 != NULL) {
		return bothLoop(head1, loop1, head2, loop2);
	}
	return NULL;
}

 剑指Offer(18)--删除有序链表中重复的节点

1->2->2->3->4->4->5,经过下面函数处理之后:

1->3->5

#include<iostream>
using namespace std;
struct ListNode
{
	int m_value;
	ListNode *m_next;
};
void DeleteDuplication(ListNode **pHead)
{
	if (pHead == nullptr || *pHead == nullptr)
		return;
	ListNode *pPreNode = nullptr;//pPreNode指向前一个不重复的节点
	ListNode *pNode = *pHead;//pNode指向待验证的节点
	while (pNode != nullptr)
	{
		ListNode *pNext = pNode->m_next;
		bool needDelete = false;
		if (pNext != nullptr && pNext->m_value == pNode->m_value)
			needDelete = true;
		if (!needDelete)
		{
			pPreNode = pNode;
			pNode = pNode->m_next;
		}
		//说明某节点的值至少重复一次
		else
		{
			int value = pNode->m_value;
			ListNode *pDelete = pNode;
			while (pDelete != nullptr && pDelete->m_value == value)
			{
				pNext = pDelete->m_next;
				delete pDelete;
				pDelete = nullptr;

				pDelete = pNext;
			}
			//头节点发生了改变(因为有重复节点)
			if (pPreNode == nullptr)
				*pHead = pNext;
			else
				pPreNode->m_next = pNext;
			pNode = pNext;
		}
	}
}
void printList(ListNode *head)
{
	while (head != nullptr)
	{
		cout << head->m_value << " ";
		head = head->m_next;
	}
	cout << endl;
}
int main(void)
{
	ListNode *m_ListNode1 = new ListNode();
	ListNode *m_ListNode2 = new ListNode();
	ListNode *m_ListNode3 = new ListNode();
	ListNode *m_ListNode4 = new ListNode();
	ListNode *m_ListNode5 = new ListNode();
	m_ListNode1->m_value = 1;
	m_ListNode1->m_next = m_ListNode2;
	m_ListNode2->m_value = 1;
	m_ListNode2->m_next = m_ListNode3;
	m_ListNode3->m_value = 2;
	m_ListNode3->m_next = m_ListNode4;
	m_ListNode4->m_value = 3;
	m_ListNode4->m_next = nullptr;
	DeleteDuplication(&m_ListNode1);
	printList(m_ListNode1);
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/83583103
今日推荐