循环链表(4) - 分割链表为两段

下面例子演示了如何分割一个链表。使用代码对其进行实现。

                                      原始的循环链表

                                     分割后的循环子链表1

                                    分割后的循环子链表2

1) 使用步进分别为1和2的算法,求得链表的中间指针以及尾指针;

2) 将后半部分链表形成循环链表;

3) 将前半部分链表形成循环链表;

4) 设置两个循环链表的头指针。

在下面的实现中,如果链表中节点个数为奇数,则前半部分链表的个数会比后半部分链表的个数多1。

代码实现:

#include <iostream>

//链表节点
struct Node
{
	int data;
	Node *next;
};

//将一个链表(head)分割为两个链表。head1和head2分别代表分割后的两个链表。
void splitList(Node *head, Node **head1, Node **head2)
{
	Node *slowPtr = head;
	Node *fastPtr = head;

	if (head == NULL)
		return;

	//如果循环链表节点个数为奇数,则最终fastPtr->next会与head重合
	//如果个数为偶数,则fastPtr->next->next会与head重合
	while (fastPtr->next != head &&
		fastPtr->next->next != head)
	{
		fastPtr = fastPtr->next->next;
		slowPtr = slowPtr->next;
	}

	//如果有偶数个节点,则移动fastPtr
	if (fastPtr->next->next == head)
		fastPtr = fastPtr->next;

	//设置前半部分的头指针
	*head1 = head;

	//设置后半部分的头指针
	if (head->next != head)
		*head2 = slowPtr->next;

	//使后半部分形成循环链表
	fastPtr->next = slowPtr->next;

	//使前半部分形成循环链表
	slowPtr->next = head;
}

//在循环链表头部插入新的节点
void push(Node **head, int data)
{
	Node *newNode = new Node;
	Node *temp = *head;
	newNode->data = data;
	newNode->next = *head;

	//如果链表不为空,则将最后一个节点的后向指针设置为新节点
	//即新节点变成了新的头节点。
	if (*head != NULL)
	{
		while (temp->next != *head)
			temp = temp->next;
		temp->next = newNode;
	}
	else
		newNode->next = newNode; //新节点做为链表第一个节点

	*head = newNode;  //调整头节点
}

//打印循环链表
void printList(Node *head)
{
	Node *temp = head;
	if (head != NULL)
	{
		do
		{
			std::cout << " " << temp->data << " ";
			temp = temp->next;
		} while (temp != head);
	}
}

int main()
{
	//初始化链表为:1->2->3->4->5->6->7
	Node *head = NULL;
	Node *head1 = NULL;
	Node *head2 = NULL;

	push(&head, 7);
	push(&head, 6);
	push(&head, 5);
	push(&head, 4);
	push(&head, 3);
	push(&head, 2);
	push(&head, 1);

	std::cout << "Original Circular Linked List \n";
	printList(head);
	std::cout << std::endl;

	//分割链表
	splitList(head, &head1, &head2);

	std::cout << "\nFirst Circular Linked List \n";
	printList(head1);
	std::cout << std::endl;

	std::cout << "\nSecond Circular Linked List \n";
	printList(head2);
	std::cout << std::endl;

	return 0;
}

输出:

Original Circular Linked List

1 2 3 4 5 6 7

First Circular Linked List

1 2 3 4

Second Circular Linked List

5 6 7

时间复杂度: O(n)

时间: 2024-10-25 06:33:21

循环链表(4) - 分割链表为两段的相关文章

【题解】环状最大两段子段和

哈哈哈哈就在快要放弃的时候盯着眼前画的图片突然之间柳暗花明( ? ?ω?? )? 首先,最大子段和想必大家都会做:对于每一个节点而言,只有选与不选两种可能的情况,枚举即可,贪心的省去一定不优的情况.然后再来考虑:如果没有环的话我们可以怎么做?没有环的情况下,我们所要做的就是找出不交叉的两个最大子段和,自然地联想到用一个分界线来分割这两个子段.g[i]代表1~i中的最大子段和,f[i]表示i~n中的最大子段和.此时的答案则是max(f[i] + g[i-1]).这几个操作的复杂度都是O(n)的.

程序员面试金典-面试题 02.04. 分割链表

题目: 编写程序以 x 为基准分割链表,使得所有小于 x 的节点排在大于或等于 x 的节点之前.如果链表中包含 x,x 只需出现在小于 x 的元素之后(如下所示).分割元素 x 只需处于“右半部分”即可,其不需要被置于左右两部分之间. 示例: 输入: head = 3->5->8->5->10->2->1, x = 5输出: 3->1->2->10->5->5->8 分析: 可以新建两个链表存储小于x的节点和大于等于x的节点,然后再将

java合并两段音频成一段 同时播放类似伴奏

/** * * @param partsPaths 要合成的音频路径数组 * @param unitedFilePath 输入合并结果数组 */ public void uniteWavFile(String[] partsPaths, String unitedFilePath) { byte byte1[] = getByte(partsPaths[0]); byte byte2[] = getByte(partsPaths[1]); byte[] out = new byte[byte1.

两段检验系统生成的identityHashCode是否重复的代码

前言:承接上一篇hashCode和identityHashCode 的关系,下面的两段简单的程序主要是检验一下系统生成的identityHashCode是否存在重复的情况. 1:可以自由控制生成对象的个数,并且不受测试的类是否重写hashCode()方法的影响 import java.util.HashSet; import java.util.Set; public class CheckSystemIdentity { public static void main(String args[

P1121 环状最大两段子段和

P1121 环状最大两段子段和 题目描述 给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 输入文件maxsum2.in的第一行是一个正整数N(N\le 2\times 10^{5})(N≤2×10?5??),表示了序列的长度. 第2行包含N个绝对值不大于10000的整数A[i],描述了这段序列,第一个数和第N个数是相邻的. 输出格式: 输入文件maxsum2.out仅包括1个整数,为最大的两段子段和是多少. 输入输出

环状最大两段子段和

题目描述 给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 输入文件maxsum2.in的第一行是一个正整数N,表示了序列的长度. 第2行包含N个绝对值不大于10000的整数A[i],描述了这段序列,第一个数和第N个数是相邻的. 输出格式: 输入文件maxsum2.out仅包括1个整数,为最大的两段子段和是多少. 输入输出样例 输入样例#1: 7 2 -4 3 -1 2 -4 3 输出样例#1: 9题解:动态规划最大两

洛谷P1121 环状最大两段子段和

题目描述 给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 输入文件maxsum2.in的第一行是一个正整数N,表示了序列的长度. 第2行包含N个绝对值不大于10000的整数A[i],描述了这段序列,第一个数和第N个数是相邻的. 输出格式: 输入文件maxsum2.out仅包括1个整数,为最大的两段子段和是多少. 输入输出样例 输入样例#1: 7 2 -4 3 -1 2 -4 3 输出样例#1: 9 说明 [样例说明]

用链表实现两个数相加

说明:使用链表实现两个数的和,数的高位存储在链表的头部,最后输出结果.注:使用了翻转链表的功能. #include<stdio.h> #include<stdlib.h> struct Node { int value; Node *next; }; Node *reverseList(Node *head) { Node *pCur=head; Node *pPre=NULL; Node *rHead=NULL; while(pCur!=NULL) { Node *pNext=p

基于十字链表的两个稀疏矩阵相乘

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef int DataType;// 稀疏矩阵的十字链表存储表示 typedef struct LNode { int i,j; // 该非零元的行和列下标 DataType e; // 非零元素值 struct LNode *right,*down; // 该非零元所在行表和列表的后继链域 }LNode, *Link; typedef str