跟左神一起练算法:在空间复杂度为0(1)的情况下判断链表是否为回文链表;将单向链表按某值划分成左边小、中间相等、右边大的形式

#include<iostream>
#include<assert.h>
using namespace std;
struct push
{
 	int value;
 	push * next;
};
struct slist
{
 	push *first;
};
void init(slist * l)
{
 	assert(l->first != nullptr);
 	l->first = nullptr;
}
void headpush(slist * l, int num)  //尾插
{
 	push * p = new push;
 	p->next = nullptr;
 	p->value = num;
 	if (l->first == nullptr)
 	{
 		 l->first = p;
  		return;
 	}
 	push *cur = l->first;
 	while (cur->next != nullptr)
 	{
 		 cur = cur->next;
 	}
 	cur->next = p;
}
void recover(slist * l,push * p)    //将链表恢复原状
{
 	push *p1 = p;
 	push *p2 = p1->next;
 	p1->next = nullptr;   //一定要在p2把结点记录之后再让p1指向空
 	push *p3 = nullptr;
 	while (p2!=nullptr)
 	{
 		 p3 = p2->next;
 		 p2->next = p1;
 		 p1 = p2;
 		 p2 = p3;
 	}
 	push * pp = l->first;    //反转完之后我又让打印了一下
 	while (pp != nullptr)
 	{
 		 cout << pp->value << endl;;
  		pp =	 pp->next;
 	}
}
void reverse(slist *l)
{
 	push *slow = l->first;
 	push *fast = l->first;
 	while (fast->next != nullptr && fast->next->next != nullptr)
 	{
  		slow = slow->next;
  		fast = fast->next->next;
 	}
 //这一步的是时候其实我们已经拿到这个链表的中间位置,其实我们想要拿到的也就是中间位置,fast指针也就没有什么用了
 	push *p1 = slow;
 	push *p2 = slow->next;
 	push *p3 = nullptr;     //p3是用来记录下一个位置的
 	p1->next = nullptr;
 	while (p2 != nullptr)    这个循环结束也就将链表的后半部分完全翻转过来
 	{
 		 p3 = p2->next;
  		p2->next = p1;
  		p1 = p2;
  		p2 = p3;
 	}//执行完毕之后p1就指向了链表的尾部
 	push *PUSH = p1;   //用这个结点把尾结点保存下来最后要用来反转恢复链表
 	//再用p1,p2两个指针一个在前一个在后,开始遍历整个链表
 	p2 = l->first; //让p1重新回到开始的位置
 	while (p2 != nullptr)  //因为之前的时候我们让slow指针在找到中点位置之后,让中点位置的next指向了nullptr
 	{
 		 if (p1->value != p2->value)
  		{
   			cout << "不是回文链表" << endl;
   			recover(l,PUSH);
   			return;    
  		}
  		p1 = p1->next;
  		p2 = p2->next;
 	}
 	cout << "是回文链表" << endl;
 	recover(l ,PUSH);
 
}
void test1()
{
 	slist s;
 	init(&s);
 	headpush(&s, 1);    //插入数据
 	headpush(&s, 2);
 	headpush(&s, 4);
 	headpush(&s, 3);
 	headpush(&s, 2);
 	headpush(&s, 1);
 	reverse(&s);
}
int main()
{
 	test1();
 	return 0;
}

思想就是:一个链表,首先使用快慢指针找到这个链表的中间位置,如果是奇数就是中间的数据,如果是偶数的话,就是中间的两个位置的前一个,找到中间位置后,再将中间位置的链表的后半部分反转
在这里插入图片描述
完成之后链表就是这个样子,然后在使用两个指针一个从头开始,一个从尾开始,判断数字是否相等,不等就返回非回文,相等就返回回文,判断完之后,再将链表反转回来。

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

#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;
struct push
{
 	int value;
 	push * next;
};
struct slist
{
 	push *first;
};
void init(slist * l)
{
 	assert(l->first != nullptr);
 	l->first = nullptr;
}
void headpush(slist * l, int num)  //尾插
{
 	push * p = new push;
 	p->next = nullptr;
 	p->value = num;
	 if (l->first == nullptr)
 	{
 		 l->first = p;
  		return;
 	}
 	push *cur = l->first;
 	while (cur->next != nullptr)
 	{
 		 cur = cur->next;
 	}
 	cur->next = p;
}
void swap(int *a, int *b)
{
 	int temp = *a;
 	*a = *b;
 	*b = temp;
}	
void func(slist *l,int num)    //正式开始的函数
{
 	vector<int>v;
 	push *cur = l->first;   //将数据拷进容器
 	while (cur != nullptr)
 	{
 		 v.push_back(cur->value);
 		 cur = cur->next;
 	}
 	int size = v.size();   //从那个这里开始进行荷兰国旗排序
 	int L = 0;
 	int less = L -1;
 	int more = size - 1;
 	while (L < more)
 	{
 		 if (v[L] > num)
  		{
   			swap(&v[L], &v[more--]);
  		}
  		else if (v[L] < num)
  		{
  			 swap(&v[++less], &v[L++]);   //和荷兰国旗一样这一步是为了处理相等问题
  		}
  		else
  		{
   			L++;
  		}
 	}
 	cur = l->first;    //然后将排好序的数组数据又重现写入链表
 	for (int i = 0; i < size; ++i)
 	{
  		cur->value = v[i];
  		cur = cur->next;
 	}
 	cur = l->first;    //这里是指为了打印验证
 	while (cur != nullptr)
 	{
 		 cout << cur->value;
 		 cur = cur->next;
 	}
}
void test()
{
 	slist s;
 	init(&s);
	 headpush(&s, 1);    //插入数据
 	headpush(&s, 2);
 	headpush(&s, 4);
 	headpush(&s, 3);
 	headpush(&s, 3);
	 headpush(&s, 6);
 	headpush(&s, 4);
 	headpush(&s, 7);
 	headpush(&s, 6);
 	func(&s,6);
}
int main()
{
 	test();
 	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值