算法设计与分析实验一:带权中位数

算法设计与分析实验一:带权中位数

1.题目重述
设有n个互不相同的元素 x1,x2,…, xn,每个元素 xi带有一个权值 wi,且∑𝑛 𝑖=1 𝑤𝑖 = 1。若元素 xk满足∑𝑥𝑖<𝑥𝑘 𝑤𝑖 ≤ 1 2 且∑𝑥𝑖>𝑥𝑘 𝑤𝑖 ≤ 1 2,则称元素 xk为 x1,x2,…, xn的带权中位数。请编写一个算法,能够在最坏情况下用 O(n)时间找出 n 个元素的带权中位数。

2.题目分析
基于寻找无序数组第k小个数的select算法,以rand()选出的pivot将数组分为三个部分,并进行前后两部分权值总和的判断。
若leftWeight <=0.5 && rightWeight <=0.5,pivot为带权中位数。否则,若leftWeight > rightWeight,则带权中位数在pivot左侧数组中,将右侧权值赋给pivot,进行递归,leftWeight<= rightWeight同理。

3.程序设计
用Term类存储元素及权值,用Term_array类存储Term动态数组,包括起始指针,数组大小和头尾等。用函数swaparr交换数组内两个元素,用函数copyele复制元素,用函数partition以xiabiaop开始划分,最后用函数isWm检查是否找到带权中位数。用cycle作循环变量,测试20组数据,每组数据用文件的形式输入。

4.代码

#include"iostream"
#include"cstdlib"
#include"fstream"
using namespace std;
class term
{
public:
	double num;
	double weight;
};
class Term_array
{
public:
	term *elmt;
	int num;
	int head;
	int tail;
	Term_array(int Element_num)
	{
		num = Element_num;
		head = 0;
		tail = num - 1;
		elmt = new term[Element_num];//记得中括号
		for (int i = 0; i < Element_num; i++)
		{
			elmt[i].num = 0;
			elmt[i].weight = 0;
		}
	}
	~Term_array()
	{
		if (elmt)
			delete[]elmt;
	}
};
void swaparr(int ele1, int ele2, Term_array &arr)
{
	double num_tmp = arr.elmt[ele1].num;
	double weight_tmp = arr.elmt[ele1].weight;
	arr.elmt[ele1].num = arr.elmt[ele2].num;
	arr.elmt[ele1].weight = arr.elmt[ele2].weight;
	arr.elmt[ele2].num = num_tmp;
	arr.elmt[ele2].weight = weight_tmp;
}
void copyele(int ele1, int ele2, Term_array &arr)
{
	arr.elmt[ele1].num = arr.elmt[ele2].num;
	arr.elmt[ele1].weight = arr.elmt[ele2].weight;
}
int partition(int p, Term_array &arr)//以下标p开始划分
{
	int start = arr.head;
	swaparr(start, p, arr);//与0号交换位置
	term tmp = arr.elmt[start];
	int l = arr.head; int r = arr.tail;
	while (l < r)
	{
		while (l < r&&arr.elmt[r].num >= tmp.num)
		{
			r--;
		}
		copyele(l, r, arr);
		while (l < r&&arr.elmt[l].num <= tmp.num)
		{
			l++;
		}
		copyele(r, l, arr);
	}
	arr.elmt[l] = tmp;
	return l;
}
int isWm(int &l, Term_array &arr)
{
	int flag = 0;
	double lsum = 0.0;
	double rsum = 0.0;
	for (int i = 0; i < l; i++)
		lsum += arr.elmt[i].weight;
	for (int i = l + 1; i < arr.num; i++)
		rsum += arr.elmt[i].weight;
	if (lsum <= 0.5&&rsum <= 0.5)
		flag = 0;
	else if (lsum < rsum)
		flag = -1;
	else if (lsum > rsum)
		flag = 1;
	return flag;
}
int main()
{
	ifstream input("exp1_in.txt");
	for (int cycle = 0; cycle < 20; cycle++)
	{
		int Element_Num = 0;
		int Wm = 0;
		input >> Element_Num;
		Term_array arr(Element_Num);
		for (int i = arr.head; i <= arr.tail; i++)
		{
			input >> arr.elmt[i].num;
		}
		for (int i = arr.head; i <= arr.tail; i++)
		{
			input >> arr.elmt[i].weight;
		}
		if (arr.num > 1)
		{
			int rand_num = (rand() % (arr.tail - arr.head + 1) + arr.head);//生成随机数
			int pos = partition(8, arr);//随机开始划分
		//接下来判断是否是带权中位数
			int flag = 0;
			while (1)
			{
				flag = isWm(pos, arr);
				if (flag == 0)//恰好是带权中位数
				{
					Wm = arr.elmt[pos].num;
					break;
				}
				else if (flag == -1)//右边大于左边,在右边找
				{
					arr.head = pos + 1;
					rand_num = (rand() % (arr.tail - arr.head + 1) + arr.head);
					pos = partition(rand_num, arr);
				}
				else if (flag == 1)
				{
					arr.tail = pos - 1;
					rand_num = (rand() % (arr.tail - arr.head + 1) + arr.head);
					pos = partition(rand_num, arr);
				}
			}
		}
		else
			Wm = arr.elmt[0].num;
		cout << Wm << endl;
	}
	return 0;
}

5.测试结果
在这里插入图片描述
附:输入文件
链接:https://pan.baidu.com/s/1zGwKLOLE5mTLJXMQg_gC3w
提取码:h0t1

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值