左神算法基础class3—题目12单向链表按某值划分成左边小、中间相等、右边大的形式

普通版:单向链表按某值划分成左边小、中间相等、右边大的形式(不用考虑稳定性且额外空间复杂度为O(n))

【题目】 给定一个单向链表的头节点head,节点的值类型是整型,再给定一个整数num。实现一个调整链表的函数,将链表调整为左部分都是值小于 num的节点,中间部分都是值等于num的节点,右部分都是值大于num的节点。
例如:链表9->0->4->5->1,num=3。 调整后链表可以是1->0->4->9->5,也可以是0->1->9->5->4。总之,满足左部分都是小于3的节点,中间部分都是等于3的节点(本例中这个部分为空),右部分都是大于3的节点即可。对某部分内部的节点顺序不做要求。

1.分析

总体思路是:左边小、中间相等、右边大的形式立马想到荷兰国旗问题(请参考荷兰国旗问题详解),考虑先把链表中的元素放入数组中,再使用荷兰国旗的方法排好序,最后把数组中的元素拷贝回链表中。

2.核心代码

(1)链表的生成及添加元素

①链表结构体定义
数据域,指针域构成

typedef struct ListNode
{
   
	int val;
	ListNode *next;
}*List;

②生成头节点
注意头节点需指向空

List MakeEmpty()
{
   
	List head = (List)malloc(sizeof(ListNode));
	head->next = NULL;
	return head;
}

③尾插法

void insert(List head, int num)
{
   
	//生成新的节点
	List p = (List)malloc(sizeof(ListNode));
	p->val = num;
	p->next = NULL;
	//遍历找到链表最后的位置
	List r = head;
	while(r->next != NULL)
	{
   
		r = r->next;
	}
	//新节点加入链表,连在末尾处
	r->next = p;	
}

(2)把链表放入数组中

使用vector容器,通过push_back()函数放入数据

vector<int> list_to_arr(List head)
{
   
	head = head->next;//跳过头节点从第一个数开始	
	vector<int> arr;
	while(head!=NULL)
	{
   
		arr.push_back(head->val);
		head = head->next;
	}
	return arr;
}

(3)荷兰国旗排序

①用变量x代表小于区域的位置、y代表大于num的区域。刚开始由于不存在小于和大于的区域,则x = -1,y = length,表示指向数组-1、length(都不存在)。再设置变量cur作为遍历的位置,刚开始cur = 0指向数组第一个数。
②.开始遍历
A.如果cur<num ,那么把cur当前的元素和小于区域的下一个数交换,即++x的位置和cur位置的数交换,cur,x后移;
B.如果cur>num,那么把cur当前的元素和大于区域的前一个数交换,即–-y的位置和cur位置的数交换,y前移,cur不变(因为交换过来的数不确定还要再判断)
C.如果cur == num,cur++。
D.如果cur == y结束。

void sort(vector<int> &arr,int num)
{
   
	int cur = 0;
	int x = -1;
	int y = arr.size();
	while(cur < y)
	{
   
		if(arr[cur] < num)
		{
   
			swap(arr[cur++],arr[++x]);
		}
		else if(arr[cur] == num)
		{
   
			cur++;
		}
		else
		{
   
			swap(arr[cur],arr[--y]);
		}
	}
}

(4)把数组放回链表中

使用vector容器的迭代器,遍历容器依次放入(或者使用for循环,这里只是想用下迭代器,好久没用了)

void arr_to_list(vector<int>arr
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值