螺丝和螺帽Nuts and bolts 《算法》2.3.15

Sedgewick 算法第四版
习题2.3.15 螺丝和螺帽:
                  “(G.J.E.Rawlins)假设有N个螺丝和N个螺帽混在一堆,你需要快速将它们配对。一个螺丝只会匹配一个螺帽,一个螺帽也只会匹配一个螺丝。你可以试着把一个螺丝和一个螺帽拧在一起看看谁大了,但不能直接比较两个螺丝或者两个螺帽。给出一个解决这个问题的有效方法。”


思路一:将quick sort略加改变。
quick sort原版是通过和一个pivot值比较,将待排序数组分为两个部分,在子数组中继续选一个pivot,这样递归地排序。这里的问题是只能比较螺丝和螺帽,所以应该改变比较的方式。
步骤:
   1)将螺丝螺帽分开。可以转化成一个只有两种值的数组的排序问题,这里不深究。
   2)选一个螺丝(也可以螺帽,之后反过来就行),以此螺丝为pivot,将螺帽分两组。
   3)以步骤2中的螺丝对应的螺帽为pivot,将螺丝分为两组
   4)经过步骤2和3,螺丝螺帽已经被分为大小两个组,然后递归地进行步骤2,3即可

#pragma once
#include 
#include 
#include 
#include 
class Nuts_And_Bolts {
	
	struct Nut
	{
		Nut(int s);
		int size;
	};

	struct Bolt
	{
		Bolt(int s);
		int size;
	};
	friend bool operator<(const Nuts_And_Bolts::Nut & n, const Nuts_And_Bolts::Bolt & b);
	friend bool operator>(const Nuts_And_Bolts::Nut & n, const Nuts_And_Bolts::Bolt & b);
	friend bool operator==(const Nuts_And_Bolts::Nut & n, const Nuts_And_Bolts::Bolt & b);
	friend bool operator<(const Nuts_And_Bolts::Bolt & b, const Nuts_And_Bolts::Nut & n);
	friend bool operator>(const Nuts_And_Bolts::Bolt & b, const Nuts_And_Bolts::Nut & n);
	friend bool operator==(const Nuts_And_Bolts::Bolt & b, const Nuts_And_Bolts::Nut & n);

	std::allocator bolt_alloc;
	std::allocator nut_alloc;
public:
	Nuts_And_Bolts(int n);//n个螺丝和n个螺帽一一配对,假设已经分成两堆,从小到大排列
	~Nuts_And_Bolts();
	void shuffle();//将螺丝和螺帽分别打乱
	void show();//按在数组中的顺序组成pair并打印出来
	Bolt* bolts;//Bolts堆
	Nut* nuts;//Nuts堆
	int size;//等于n	
};

void sort(Nuts_And_Bolts& nb);//好名字。。。

#include "exercise2.3.15.h"
bool operator<(const Nuts_And_Bolts::Nut & n, const Nuts_And_Bolts::Bolt & b)
{
	return n.size(const Nuts_And_Bolts::Nut & n, const Nuts_And_Bolts::Bolt & b)
{
	return n.size>b.size;
}

bool operator==(const Nuts_And_Bolts::Nut & n, const Nuts_And_Bolts::Bolt & b)
{
	return n.size == b.size;
}


void sort_impl(Nuts_And_Bolts& nb, int lo, int hi)
{
	if (lo >= hi)
		return;
	//以bolts[lo]为pivot,对nuts排序
	//双指针,两头向中间扫描并交换的快排
	int beg = lo;
	int end = hi;
	auto pivot_b = nb.bolts[lo];
	using std::swap;
	while (true) {
		while (beg <= hi&&nb.nuts[beg] < pivot_b) {
			++beg;
		}
		while (end >= lo&&nb.nuts[end] > pivot_b) {
			--end;
		}
		if (beg > end) {//将在lo中存放的匹配的nut放到合适的位置
			swap(nb.nuts[lo], nb.nuts[--beg]);
			break;
		}
		if (beg == end) {
			break;
		}
		if (nb.nuts[beg] == pivot_b || nb.nuts[end] == pivot_b) {//如果遇见了匹配的nut
			if (nb.nuts[beg] == pivot_b) {//将匹配的nuts暂时放到lo
				if (beg == lo) {//如果beg本来就是lo就会导致死循环
					++beg;
				}
				else {
					swap(nb.nuts[lo], nb.nuts[beg]);
				}
			}
			else {
				swap(nb.nuts[end], nb.nuts[lo]);
			}
			//beg,end不移动以待下一轮处理
		}
		else {//如果没有遇见匹配的nut
			swap(nb.nuts[beg], nb.nuts[end]);
			++beg;
			--end;
		}
	}
	//通过pivot_b将nuts排完了序
	//现在通过pivot_n将bolt排序
	auto pivot_n = nb.nuts[beg];
	beg = lo;
	end = hi;
	while (true) {
		while (beg <= hi&&nb.bolts[beg] < pivot_n) {
			++beg;
		}
		while (end >= lo&&nb.bolts[end] > pivot_n) {
			--end;
		}
		if (beg > end) {//将在lo中存放的匹配的nut放到合适的位置
			swap(nb.bolts[lo], nb.bolts[--beg]);
			break;
		}
		if (beg == end) {
			break;
		}
		if (nb.bolts[beg] == pivot_n || nb.bolts[end] == pivot_n) {//如果遇见了匹配的nut
			if (nb.bolts[beg] == pivot_n) {//将匹配的nuts暂时放到lo
				if (beg == lo) {//如果beg本来就是lo就会导致死循环
					++beg;
				}
				else {
					swap(nb.bolts[lo], nb.bolts[beg]);
				}
			}
			else {
				swap(nb.bolts[end], nb.bolts[lo]);
			}
			//beg,end不移动以待下一轮处理
		}
		else {//如果没有遇见匹配的nut
			swap(nb.bolts[beg], nb.bolts[end]);
			++beg;
			--end;
		}
	}
	//现在bolts也排了序
	//beg是匹配的位置
	sort_impl(nb, lo, beg - 1);
	sort_impl(nb, beg + 1, hi);
}

void sort(Nuts_And_Bolts & nb)
{
	nb.shuffle();//打乱以保证快排效率
	sort_impl(nb, 0, nb.size - 1);
}

bool operator<(const Nuts_And_Bolts::Bolt & b, const Nuts_And_Bolts::Nut & n)
{
	return b.size(const Nuts_And_Bolts::Bolt & b, const Nuts_And_Bolts::Nut & n)
{
	return b.size>n.size;
}

bool operator==(const Nuts_And_Bolts::Bolt & b, const Nuts_And_Bolts::Nut & n)
{
	return b.size==n.size;
}

Nuts_And_Bolts::Nut::Nut(int s) :size(s)
{
}

Nuts_And_Bolts::Bolt::Bolt(int s) : size(s)
{
}

Nuts_And_Bolts::Nuts_And_Bolts(int n)
{
	bolts = bolt_alloc.allocate(n);
	nuts = nut_alloc.allocate(n);
	for (int i = 0; i < n; ++i) {//从0到n-1,螺丝螺帽一一配对,已经从小到大排序好
		bolt_alloc.construct(bolts + i, i);
		nut_alloc.construct(nuts + i, i);
	}	
	size = n;
}

Nuts_And_Bolts::~Nuts_And_Bolts()
{
	for (int i = 0; i < size; ++i) {
		bolt_alloc.destroy(bolts + i);
		nut_alloc.destroy(nuts + i);
	}
	bolt_alloc.deallocate(bolts, size);
	nut_alloc.deallocate(nuts, size);
}

void Nuts_And_Bolts::shuffle()
{
	static std::default_random_engine rgen(time(nullptr));
	static std::uniform_int_distribution<> dis;
	using std::swap;
	for (int i = 0; i < size; ++i) {
		swap(bolts[i], bolts[dis(rgen, decltype(dis)::param_type(0, i))]);
		swap(nuts[i], nuts[dis(rgen, decltype(dis)::param_type(0, i))]);
	}
}

void Nuts_And_Bolts::show()
{
	for (int i = 0; i < size; ++i) {
		std::cout << " ( " << bolts[i].size << " , " << nuts[i].size << " ) " << std::endl;
	}
	std::cout << std::endl;
}


    
 

你可能感兴趣的:(算法思路备忘)