C++中的链表基础

C++中的链表基础

1.链表节点

struct ListNode {
	int val; //这个成员变量存储节点的值,它的类型是整数。
	ListNode* next; //这是一个指针,指向下一个 ListNode 类型的节点,用于连接链表中的下一个元素
	ListNode() : val(0), next(nullptr) {} //这是一个无参构造函数,当没有提供初始值时,它会创建一个值为 0,next 指针为 nullptr 的节点。
	ListNode(int x) : val(x), next(nullptr) {} //单参构造
	ListNode(int x, ListNode* next) : val(x), next(next) {}
};

2.建立链表

用数组输入

ListNode* vector_Createlist(vector<int> v, int n)
{
	cout << "Input ListNode:" << endl;
	//int Inputnum;
	ListNode* head, * nodetemp, * node; //建立三个节点指针
	head = nullptr;
	nodetemp = nullptr;
	
	for(int i = 0;i<n;i++)
	{
		node = new ListNode;//创建新节点,调用了 ListNode 的默认构造函数,该构造函数将 ListNode 对象的 val 成员初始化为 0,next 成员初始化为 nullptr
		node->val = v[i];

		if (head == nullptr) {
			head = node;
		}
		else {
			nodetemp->next = node;
		}
		nodetemp = node;
		nodetemp->next = nullptr;
	}
	return head;
}

3.输出链表

void PrintList(ListNode* head)
{
	cout << "printList" << endl;
	ListNode* current = head;//声明了一个指针 current,并初始化它指向链表的头节点 head。current 将用于遍历链表的每个节点。
	while (current != nullptr) {
		cout << current->val << " ";
		current = current->next;
	}
	cout << endl;
}

21 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:
输入:l1 = [], l2 = []
输出:[]

示例 3:
输入:l1 = [], l2 = [0]
输出:[0]

使用递归方法

ListNode* mergeTwoLists(ListNode* list1, ListNode* list2)//21 合并两个有序链表
{
	if (list1 == nullptr)
	{
		return list2;
	}
	else if (list2 == nullptr)
	{
		return list1;
	}
	else if (list1->val < list2->val)
	{
		list1->next = mergeTwoLists(list1->next, list2);
		return list1;
	}
	else
	{
		list2->next = mergeTwoLists(list1, list2->next);
		return list2;
	}
}

141.环形链表

判断链表是否有环

bool hasCycle(ListNode* head)//141.环形链表
{
	unordered_set<ListNode*> set;//将指针存放在哈希表中
	ListNode* current = head;
	while (current != nullptr)
	{
		if (set.count(current))//set元素唯一,所以set.count()是0或1,1是true,遇到重复,有环
		{
			return true;
		}
		set.insert(current);
		current = current->next;
	}
	return false;
}

206.反转链表

ListNode* reverseList(ListNode* head) {
	ListNode* prev = nullptr;
	ListNode* curr = head;
	while (curr) {
		ListNode* next = curr->next;//next 指向与 curr->next 相同的内存位置,即head的下一个节点
		curr->next = prev;
		prev = curr;//移动prev指针到curr指针同位置
		curr = next;//更新curr指针
	}
	return prev;
}

很考验对链表的理解
找的一个视频讲解206.反转链表

2095.删除链表中间节点

给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。
长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点(下标从 0 开始),其中 ⌊x⌋ 表示小于或等于 x 的最大整数。
对于 n = 1、2、3、4 和 5 的情况,中间节点的下标分别是 0、1、1、2 和 2 。

关键在于找中间节点位置用快慢指针

ListNode* deleteMiddle(ListNode* head)//2095.删除链表中间节点
{
    if (head == nullptr || head->next == nullptr)//输入的链表是空或是有一个元素
    {
	return nullptr;
    }
	ListNode* fast = head;
	ListNode* slow = head;
	ListNode* pre = nullptr;
	
	while (fast != nullptr && fast->next != nullptr )//双指针找中间节点的条件
	{
		fast = fast->next->next;
		pre = slow;
		slow = slow->next;//快慢指针找到中间元素
	}
	pre->next = pre->next->next;
	return head;
}

双指针找中间节点

while (fast != nullptr && fast->next != nullptr )//双指针找中间节点的条件
	{
		fast = fast->next->next;
		slow = slow->next;//快慢指针找到中间元素
	}

奇数和偶数个数节点结果

C++中的链表基础_第1张图片

328.奇偶链表

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。
第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。
请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。
你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

用两个指针相互向后移动,注意条件

ListNode* oddEvenList(ListNode* head) {
	if (head == nullptr || head->next == nullptr) {
		return head;
	}

	ListNode* odd = head;
	ListNode* even = head->next;
	ListNode* evenHead = even; // 保存偶数节点的头指针

	while (even != nullptr && even->next != nullptr) {
		odd->next = even->next; 
		odd = odd->next; 

		even->next = odd->next; 
		even = even->next; // 当代码执行 even = even->next 时,如果 even->next 是 nullptr,则 even 将被赋值为 nullptr,不会出错
	}

	odd->next = evenHead; // 将偶数节点连接到奇数节点末尾

	return head;
}

2130.链表最大孪生和

在一个大小为 n 且 n 为 偶数 的链表中,对于 0 <= i <= (n / 2) - 1 的 i ,第 i 个节点(下标从 0 开始)的孪生节点为第 (n-1-i) 个节点 。
比方说,n = 4 那么节点 0 是节点 3 的孪生节点,节点 1 是节点 2 的孪生节点。这是长度为 n = 4 的链表中所有的孪生节点。
孪生和 定义为一个节点和它孪生节点两者值之和。
给你一个长度为偶数的链表的头节点 head ,请你返回链表的 最大孪生和 。

输入:head = [5,4,2,1]
输出:6
解释:
节点 0 和节点 1 分别是节点 3 和 2 的孪生节点。孪生和都为 6 。
链表中没有其他孪生节点。
所以,链表的最大孪生和是 6 。

用数组做

int pairSum(ListNode* head)//2130.链表最大孪生和
{
	vector<int> v;
	ListNode* node = head;
	while (node != nullptr)
	{
		v.push_back(node->val);
		node = node->next;
	}
	int n = v.size();
	int max_sum = INT_MIN;
	for (int i = 0; i < n / 2; i++)
	{
		v[i] = v[i] + v[n - 1 - i];
		max_sum = max(max_sum, v[i]);
	}
	return max_sum;
}

快慢指针找到链表中心,后半部分链表反转,这样前后部分都可以同时向后移动求和

int pairSum1(ListNode* head)//2130.链表最大孪生和
{
	if (head == nullptr || head->next == nullptr) return 0;
	ListNode* slow = head;
	ListNode* fast = head->next;
	while (fast != nullptr && fast->next != nullptr)//快慢指针找中心节点固定写法
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	slow = slow->next;//翻转从中心slow下一个开始
	ListNode* pre = nullptr;
	ListNode* curr = slow;
	while (curr)//链表翻转,注意反转完头节点是pre
	{
		ListNode* next = curr->next;
		curr->next = pre;
		pre = curr;
		curr = next;
	}
	int max_sum = INT_MIN;
	while (pre)
	{
		max_sum = max(max_sum, head->val + pre->val);
		pre = pre->next;
		head = head->next;
	}
	return max_sum;
}

你可能感兴趣的:(c++,链表,开发语言)