• 2015年阿里研发工程师实习笔试附加题


    题目1:

    常常会有频繁申请、释放内存的需求,比如在发送网络报文时,每次都要分配内存以存储报文,等报文发送完成后又需要删除报文。
    为了避免频繁的new/delete对系统带来的开销,需要实现一个通用的FreeList机制。使用者总是从free list中分配内存,如果存在没有使用的内存块就直接摘出来使用,如果没有的话再从系统中分配。使用完毕后并不去直接delete该内存块,而是交给FreeList保管。
    要求:

    1. 实现一个对固定大小内存块进行管理的通用FreeList类,给出定义和实现。要求不能使用STL中的容器类。定义类的接口和实现时注意通用性、健壮性和可测试性。
    2. 如果该类的对象可能会被多个thread同时访问,请描述如何怎样保证线程安全。有没有办法在保证线程安全的同时尽可能增大并发度?如果有也请描述你的思路。
    #include <bits/stdc++.h>
    #include <Windows.h>
    //#include <afxmt.h>
    using namespace std;
    const int N = 32;
    template<typename T>
    class MemoryPool {
    public:
    	MemoryPool() { Expand(); };
    	MemoryPool(size_t cnt) {
    		Expand();
    	}
    	~MemoryPool() {
    		MemoryPool<T> *pNext = nullptr;
    		for (pNext = FreeList; pNext != nullptr;pNext=FreeList) {
    			FreeList = FreeList->FreeList;
    			delete[](char*)pNext;
    		}
    	}
    	void *Alloc() {
    		if (FreeList == nullptr) 
    			Expand();
    		MemoryPool<T>* p = nullptr;
    		p = FreeList;
    		FreeList = FreeList->FreeList;
    		return p;
    	}
    	void Free(void *p){
    		MemoryPool<T> *tmp = nullptr;
    		tmp = static_cast<MemoryPool<T>*>(p);
    		tmp->FreeList = FreeList;
    		FreeList = tmp;
    	}
    	void Expand(int cnt = N) {
    		size_t size = max(sizeof(T) , sizeof(MemoryPool<T>*));
    		MemoryPool<T> *LastItem = static_cast<MemoryPool<T>*>(static_cast<void *>(new char[size]));
    		FreeList = LastItem;
    		for (int i = 0; i < cnt; i++) {
    			LastItem->FreeList = static_cast<MemoryPool<T>*>(static_cast<void *>(new char[size]));
    			LastItem = LastItem->FreeList;
    		}
    		LastItem->FreeList = nullptr;
    	}
    	MemoryPool<T> *FreeList;
    };
    
    class CriticalSection{
    public:
    	CriticalSection() {
    		InitializeCriticalSection(&cs);
    	}
    	~CriticalSection() {
    		DeleteCriticalSection(&cs);
    	}
    	void Lock() {
    		EnterCriticalSection(&cs);
    	}
    	void Unlock() {
    		LeaveCriticalSection(&cs);
    	}
    	CRITICAL_SECTION cs;
    };
    template<typename T,typename L>
    class MTMemoryPool {
    public:
    	MTMemoryPool() {};
    	void *Alloc() {
    		void *p = nullptr;
    		lock.Lock();
    		p = pool.Alloc();
    		lock.Unlock();
    		return p;
    	}
    	void Free(void *p) {
    		lock.Lock();
    		pool.Free(p);
    		lock.Unlock();
    	}
    	T pool;
    	L lock;
    };
    
    class Node {
    public:
    	static void *inew() {
    		void *p = s_pool->Alloc();
    		return p;
    	}
    	static void idelete(void *p) {
    		s_pool->Free(p);
    	}
    	static void NewPool() {
    		s_pool = new MTMemoryPool<MemoryPool<Node>, CriticalSection>;
    	}
    	static void DeletePool() {
    		delete s_pool;
    		s_pool = nullptr;
    	}
    	static MTMemoryPool<MemoryPool<Node>, CriticalSection> *s_pool;
    };
    MTMemoryPool<MemoryPool<Node>, CriticalSection> *Node::s_pool = nullptr;
    
    void fun() {
    	Node *test[100005];
    	for (int i = 0; i <= 100000; i++) {
    		test[i] = new Node;
    	}
    	for (int i = 0; i <= 100000; i++) {
    		delete test[i];
    	}
    }
    void ifun() {
    	Node *test[100005];
    	for (int i = 0; i <= 100000; i++) {
    		test[i]=(Node*)Node::inew();
    	}
    	for (int i = 0; i <= 100000; i++) {
    		Node::idelete(test[i]);
    	}
    }
    int main() {
    	int start = clock();
    	fun();
    	printf("%d
    ", clock() - start); //GetTickCount();
    	start = clock();
    	Node::NewPool();
    	ifun();
    	Node::DeletePool();
    	printf("%d
    ", clock() - start);
    	return 0;
    }
    

    可能由于只用一个线程什么的,用了临界区等,反而时间慢了一倍。。。

    题目2:

    假设这样一个场景:当很多用户并发获取服务,server端资源不足时,希望用户能够按照预先分配的配额来使用资源。
    比如预先定义好user1, user2, user3的配额是20%, 30%, 50%,资源争抢时希望服务器有20%的服务能力分配给user1, 30%给user2, 50%给user3。
    但是如果某个时刻只有user1的请求,server还是要把100%的服务能力分配给user1以充分利用资源;又如某个时间段只有user2/user3在访问服务,则按照30%:50%的比率来分配资源。

    需要通过一个类似于队列的ManagedQueue类来封装上述功能。
    入队的时候需要提供user id(32位正整数)以及用户的任务(Task)。我们假设系统的用户数是有上限的,不会超过10个。

    当队列中各个用户的请求均非空时,要求出队的task分布符合用户的配额设置。延续上面的例子如果连续出队100次,要求user1的task有20个左右,user2的task 30个左右, user3的50个左右。

    这里出队的task恰好能对应服务器的服务能力。

    要求:

    1. 给出关键数据结构以及ManagedQueue的定义。用户任务Task可以认为是一个已经实现的类来使用。可以使用STL容器类。
    2. 实现出队方法Dequeue(),请尽可能写健壮的代码
      注意:这里并不要求精确的按照比例分配任务,只要统计意义上满足预定义的配额比例就可以了。
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 25;
    struct ManagedQueue {
    	int id;
    	int data;
    };
    deque<ManagedQueue> dq;
    
    struct Node {
    	bool flag;
    	int cnt;
    };
    void fun(int x) {
    
    }
    void test(vector<int> v,int cnt) {
    	vector<ManagedQueue>g;
    	vector<Node>c;
    	while (!dq.empty()) {
    		c.clear(); g.clear();
    		for (int i = 0; i < v.size(); i++)
    			c.push_back(Node{ 0,0 });
    		for (int i = 0; i < cnt; i++) {
    			g.push_back(dq.front());
    			c[dq.front().id].flag = true;
    			dq.pop_front();
    		}
    		int total = 0;
    		for (int i = 0; i < v.size(); i++) {
    			if (c[i].flag) {
    				total += v[i];
    			}
    		}
    		for (int i = 0; i < v.size(); i++) {
    			if (c[i].flag) {
    				c[i].cnt = max(1,cnt*v[i] / total);
    			}
    		}
    		for (int i = 0; i < cnt; i++) {
    			if (c[g[i].id].cnt > 0) {
    				fun(g[i].data);
    				c[g[i].id].cnt--;
    			}
    			else {
    				dq.push_front(g[i]);
    			}
    		}
    	}
    }
    int main() {
    	//init dq;
    	vector<int> v = { 2,3,5 };
    	int cnt=100;
    	test(v,cnt);
    	return 0;
    }
    

    题目3:

    分布式系统中的RPC请求经常出现乱序的情况。
    写一个算法来将一个乱序的序列保序输出。例如,假设起始序号是1,对于(1, 2, 5, 8, 10, 4, 3, 6, 9, 7)这个序列,输出是:
    1
    2
    3, 4, 5
    6
    7, 8, 9, 10

    上述例子中,3到来的时候会发现4,5已经在了。因此将已经满足顺序的整个序列(3, 4, 5)输出为一行。

    要求:

    1. 写一个高效的算法完成上述功能,实现要尽可能的健壮、易于维护
    2. 为该算法设计并实现单元测试
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 25;
    int a[N];
    int vis[N];
    int main() {
    	int n; cin >> n;
    	for (int i = 1; i <= n; i++) {
    		cin >> a[i];
    	}
    	int j = 1;
    	for (int i = 1; i <= n; i++) {
    		vis[a[i]] = 1;
    		if (a[i] == j) {
    			while (vis[j]) {
    				printf("%d ", j);
    				j++;
    			}
    			printf("
    ");
    		}
    	}
    	return 0;
    }
    

    不知道对不

  • 相关阅读:
    【转】使用外部看门狗请三思!
    【转】一招解决MCU启动异常
    【转】电源芯片选型,容易忽略的“QC”
    【转】为什么 MQTT 是最适合物联网的网络协议
    【转】中国芯酸往事
    函数输入参数类型为枚举时,则限定函数参数的接收范围,非枚举值输入则错误
    函数形参为指针与非指针的区别
    【转】函数中的形参问题(指针形参、引用形参、二重指针作为形参)
    【转】Example of using the --info linker option
    【转】STM32
  • 原文地址:https://www.cnblogs.com/HaibaraAi/p/4401130.html
Copyright © 2020-2023  润新知