算法题目打卡:Ques20201017

1. 单机作业调度(n个顾客等待同一服务)

问题描述

设有n个顾客同时等待同一服务,顾客i需要的服务时间为t,1<=i<=n,应如何安排n个顾客的服务次序才能使总的等待时间达到最小?总的等待时间是各顾客等待服务的总和。试给出你的做法的理由。

使用贪心策略,将服务所需时间按从小到大进行排列,优先安排服务时间短的。

证明(交换论证)

2.  最优前缀码-Huffman编码

定义

二元前缀码:表示一个字符的0,1字串不能是表示另一个字符的0,1字串的前缀。

B=∑f(xi)d(xi)是存储一个字符的平均值。d(xi)为码长。

平均码长达到最小的前缀编码方案称为字符集C的一个最优前缀编码

 

不同的字符

a

b

c

d

e

f

频率f(千次)

45

13

12

16

9

5

定长码

000

001

010

011

100

101

变长码

0

101

100

111

1101

1100

伪代码

证明

C++代码

// 最优前缀码-Huffman编码
//二元前缀码:表示一个字符的0, 1字串不能是表示另一个字符的0, 1字串的前缀。
//B = ∑f(xi)d(xi)是存储一个字符的平均值。d(xi)为码长。
//平均码长达到最小的前缀编码方案称为字符集C的一个最优前缀编码。
//例:字符集及其频率如
//表.长为100000的文件:
//定长码:300000 bit,
//变长码:224000, 省25 %

// 算法:要点:编码字符均在叶子节点上,数据结构:队列中装树的结点,队列递增排序,取最小元素赋值给树节点左边右边,插入新节点后仍然递增,注意频率

//算法复杂度:
//2行排序O(nlogn)
//3行循环n - 1次
//8行循环体内插入操作
//O(logn),其它操作常量
//所以T(n) = O(nlogn)


// 关键词:贪心

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue> // 使用队列
#include<cstring>
#include <string>
using namespace std;
struct Huffman { // 存字符及其对应的频率 结构
	string character; // 编码字符
	float frequency;
};

struct Node { // 树结点结构
	Huffman data;
	Node* lChild;
	Node* rChild;
	Node(Huffman data)
	{
		this->data = data;
		this->lChild = NULL;
		this->rChild = NULL;
	}
};

class MinHeap {//最小堆 min堆的实现 参考 https://blog.csdn.net/u010900754/article/details/54804303
private:
	int size = 0;
	vector<Huffman> heap;
public:
	int getSize() {
		return heap.size();
	}
	Huffman getElement(int i) {
		return heap[i];
	}
	void add(Huffman &data) { // 添加一个元素,需要插在哪里的问题
		heap.push_back(data);
		
		int i = heap.size() - 1;
		while (i > 0 && heap[i].frequency < heap[(i - 1) / 2].frequency) { //比较的是频率大小
			swap(i, (i - 1) / 2);
			i = (i - 1) / 2;
		}
	}

	Huffman top() { //取走root结点,也需要调整堆中结点的位置
		/*size--;*/
		Huffman r = heap[0];
		//swap(heap.size()-1, 0); // 交换是个什么操作??
		vector<Huffman> T;
		T.insert(T.begin(), heap.begin()+1, heap.end());
		heap = T;
		minheapify(0);
		return r;
	}

	void minheapify(int i) {
		int l = 2 * i + 1;
		int r = 2 * i + 2;
		int small = i;
		if (l < heap.size() && heap[i].frequency > heap[l].frequency) {
			small = l;
		}
		if (r < heap.size() && heap[r].frequency < heap[small].frequency) {
			small = r;
		}
		if (i != small) {
			swap(i, small);
			minheapify(small);
		}
	}

	void swap(int i, int j) {
		Huffman temp = heap[i];
		heap[i] = heap[j];
		heap[j] = temp;
	}
};


class Ques20201017
{
public:

	void test(vector<string>& characters, vector<float>& frequencys) {
		vector<Huffman> huffmans=init(characters, frequencys);
		// 将数组中的元素进行排序,还是直接在一开始就赋值给队列?==>维护最小堆
		MinHeap minheap = MinHeap();
		for (int i = 0; i < characters.size(); i++) {
			minheap.add(huffmans[i]);
		}
		//huffmans = minheap.getElement();// 得到排好序的数组
		// 开辟叶结点
		vector<Node*> que;							
		while(minheap.getSize()!=1) {
			Huffman h1 = minheap.getElement(0);// 得到最小元素			
			Node* node1 = new Node(h1);
			que.push_back(node1);
			minheap.top();
			Huffman h2 = minheap.getElement(0);// 得到第2小元素		
			Node* node2 = new Node(h2);		
			que.push_back(node2);			
			minheap.top();// 放入队列后就可以删除了
			float fx = h1.frequency;
			float fy = h2.frequency;
			float fz = fx + fy;
			// 新的第3个节点 
			Huffman temp;
			temp.frequency = fz; // 无字符
			temp.character = "O";
			Node* mergeNode = new Node(temp);	
			minheap.add(temp); // 将第3个新增加的也添加进最小堆排序
			mergeNode->lChild = node1;
			mergeNode->rChild = node2;

			
		}
		Huffman last = minheap.getElement(0);// 得到最小元素			
		Node* lastnode = new Node(last);
		que.push_back(lastnode);
		// 打印结果
		for (int i = que.size()-1; i >=0 ;i--) {
			cout << " " << que[i]->data.character;
			cout << endl;
		}

	}

private:
	vector<Huffman> init(vector<string> &characters, vector<float> &frequencys) {
		vector<Huffman> huffs;
		for (int i = 0; i < characters.size();i++) {
			Huffman h = Huffman();
			h.character = characters[i];
			h.frequency = frequencys[i];
			huffs.push_back(h);
		}
		return huffs;
	}
};

int main() {
	Ques20201017 ques = Ques20201017();
	vector<string> s = {"a","b","c", "d", "e","f"};
	vector<float> freq = {45,13,12,16,9,5 };
	ques.test(s, freq);
	return 0;
}

运行效果

貌似还有些不完善的,比如如何去遍历这棵树的问题,作业太多就先不搞了= =

猜你喜欢

转载自blog.csdn.net/Toky_min/article/details/109048313