c/c++ 测试题
- 1 根据以下提示代码,实现相应功能。查找函数性能要求为 o(1)
typedef struct peer {
struct in_addr remote_addr;
struct peer *next;
void *data;
} peer_t;
peer_t *peers[256];
peer_t * peer_lookup(uint32_t addr, peer_t **peers);
peer_t * peer_add(uint32_t addr, peer_t **peers);
int peer_remove(uint32_t addr, peer_t **peers);
实现的完整代码为:
#include <arpa/inet.h>
#include <iostream>
using namespace std;
typedef struct peer {
struct in_addr remote_addr;
struct peer *next;
void *data;
} peer_t;
peer_t * peers[256];
peer_t * peer_lookup(uint32_t addr, peer_t **peers);
peer_t * peer_add(uint32_t addr, peer_t **peers);
int peer_remove(uint32_t addr, peer_t **peers);
peer_t * peer_lookup(uint32_t addr, peer_t **peers)
{
std::hash<uint32_t> hash_fn;
size_t hash_code = hash_fn(addr) % 256;
peer_t * ppeer = NULL;
if (ppeer = peers[hash_code])
{
while (ppeer) {
if (ppeer->remote_addr.s_addr = htonl(addr)) {
cout << "lookup node ok" << endl;
break;
}
}
}
return ppeer;
}
//ntohl()
peer_t * peer_add(uint32_t addr, peer_t **peers)
{
std::hash<uint32_t> hash_fn;
size_t hash_code = hash_fn(addr) % 256;
auto peer = new peer_t;
peer->remote_addr.s_addr = htonl(addr);
peer->data = NULL;
if (peers[hash_code] == NULL) {
peers[hash_code] = peer;
peer->next = NULL;
}
else {
peer->next = peers[hash_code];
peers[hash_code] = peer;
}
return peer;
}
int peer_remove(uint32_t addr, peer_t **peers)
{
int ret = -1;
std::hash<uint32_t> hash_fn;
size_t hash_code = hash_fn(addr) % 256;
peer_t * prev = NULL, * ppeer = NULL;
if (ppeer = peers[hash_code])
{
while (ppeer) {
if (ppeer->remote_addr.s_addr = htonl(addr)) {
if (NULL == prev) {
peers[hash_code] = ppeer->next;
}
else {
prev->next = ppeer->next;
}
delete ppeer;
cout << "deleet node from hash table" << endl;
ret = 0;
break;
}
prev = ppeer;
}
}
return ret;
}
int main(int argc, char **argv)
{
for(auto i=0; i<256; i++) {
peers[i] = NULL;
}
cout << "now insert node" << endl;
auto peer1 = peer_add(123, peers);
auto peer2 = peer_add(456, peers);
cout << endl << "after insert node 123, 456" << endl;
auto ppeer = peer_lookup(123, peers);
if (ppeer) {
cout << "peer node's addr : " << ntohl(ppeer->remote_addr.s_addr) << endl;
}
ppeer = peer_lookup(456, peers);
if (ppeer) {
cout << "peer node's addr : " << ntohl(ppeer->remote_addr.s_addr) << endl;
}
cout << endl << "remove node 123" << endl;
if (0 == peer_remove(123, peers)) {
cout << "remvoe peer node whose id is 123" << endl;
}
cout << endl << "after remove node 123" << endl;
ppeer = peer_lookup(123, peers);
if (ppeer) {
cout << "peer node's addr : " << ntohl(ppeer->remote_addr.s_addr) << endl;
}
ppeer = peer_lookup(456, peers);
if (ppeer) {
cout << "peer node's addr : " << ntohl(ppeer->remote_addr.s_addr) << endl;
}
}
测试结果:
[root@bogon mianshi]# g++ main.cc
[root@bogon mianshi]# ./a.out
now insert node
after insert node 123, 456
lookup node ok
peer node's addr : 123
lookup node ok
peer node's addr : 456
remove node 123
deleet node from hash table
remvoe peer node whose id is 123
after remove node 123
lookup node ok
peer node's addr : 456
[root@bogon mianshi]#
真正的lookup为o(1)需要用rehash解决哈稀冲突。
解决哈西冲突前提是散列表可以扩容,peers数组需要从固定256个变成**,另外申请一个size_t len记录槽位容量。
- 2 实现⼀个 timer ,有什么数据结构可以选择?请举2个以上例⼦并给出简要说明
散列表作为定时器挂载的数据结构,使用时间轮模型,详情请参照博客:fastdfs定时器设计
std::multimap容器,保存的有序的键/值对,元素可以重复。(满足定时器最重要的两个应用指标:有序性,探针定时时间可以精确设置为下一次的超时时间;可在同一个时间戳定义多个不同的定时任务)
github定时器项目地址
红黑树
定时器的实现原理都比较相近。每种定时器都有适应的业务场景:
大量时间间隔相同的事件,用散列表管理 ,反正执行顺序,和放入的顺序一样。
其他的用堆,减少堆上数据 ,减少维护,防止“爆堆”。
不同的定时器之间,性能差异是在定时时间调整,定时任务插入,定时任务获取,和灵活性,扩展性,这些指标与业务场景的适配通常是一种平衡。
- 3 是否有⾃⼰造轮⼦的经验?请简要描述
线程池,使用reactor模型。采用队列注入任务,条件变量通讯,master管理业务线程执行。
线程池博客地址
golang 试题
- 请实现 Check 函数,调⽤ check_word_correct
package main
/*
#include <stdio.h>
#include <stdlib.h>
int check_word_correct(const char **texts, int &correct_level)
{
;
}
*/
import "C"
import (
"fmt"
"time"
)
// 返回值: 正确级别 [0,10]
func Check(texts []string) (int, error) {
arg := make([](*C.char), 0) //C语言char*指针创建切片
l := len(texts)
for i,_ := range texts{
char := C.CString(texts[i])
defer C.free(unsafe.Pointer(char)) //释放内存
strptr := (*C.char)(unsafe.Pointer(char))
arg = append(arg, strptr) //将char*指针加入到arg切片
}
var level int;
ret := C.check_word_correct((**C.char)(unsafe.Pointer(&arg[0])), &level)
if ret == 0 {
return level, nil
} else {
return level, errors.New("C.check_word_correct occured some error")
}
}
func main() {
texts := []string{"aa", "bb", "cc"}
Check(texts)
}
- PCM2File 函数的功能是把 16 位采样深度的 PCM 数据写⼊⽂件。请参考 pcm2Bytes , 实现
File2PCM 函数从⽂件中把相应的 PCM 数据读取出来并给出必要的注释
func pcm2Bytes(floats []float32) []byte {
buf := make([]int16, len(floats))
for i, f := range floats {
buf[i] = int16(f)
}
var bytes []byte
l := int(unsafe.Sizeof(buf[0])) * len(buf)
x := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
x.Data = uintptr(unsafe.Pointer(&buf[0]))
x.Len = int(l)
x.Cap = int(l)
return bytes
}
func PCM2File(file string, pcm []float32) error {
return ioutil.WriteFile(file, pcm2Bytes(pcm), 0600)
}
func Bytes2pcm(bytes []byte) []float32 {
buf := make([]float32, len(bytes)/2)
i := 0
for {
temp := int16(bytes[i]) + int16(bytes[i+1]) * 256
buf[i/2] = float32(temp)
i = i + 2
if i >= len(bytes) {
break
}
}
return buf
}
func File2PCM(file string) ([]float32, error) {
var fdata[]byte
fdata, err := ioutil.ReadFile(file)
if err != nil {
return []float32, errors.New("read from file error")
}
return Bytes2pcm(), nil
}
- 实现⼀个允许超时的 chan string 接收器
package main
import (
"fmt"
"time"
"strconv"
)
func main() {
ch := make(chan string)
quit := make(chan bool)
go func() {
for i := 0; i < 15; i++ {
ch <- strconv.Itoa(i)
time.Sleep(time.Second)
}
}()
go func() {
timeout := time.After(time.Second * 3)
flagrun := true
for ; flagrun == true ; {
select {
case <-timeout:
fmt.Println("3秒定时器超时,向退出通道发送信号,使能进程退出。或向其它业务发出信号,实现状态回传")
flagrun = false
quit <- true
case str := <-ch:
fmt.Println("string: ", str)
}
}
}()
<-quit
close(ch)
close(quit)
fmt.Println("程序结束")
}
测试结果:
[root@bogon mianshi]# go build main.go
[root@bogon mianshi]# ./main
string: 0
string: 1
string: 2
3秒定时器超时,向退出通道发送信号,使能进程退出。或向其它业务发出信号,实现状态回传
程序结束
[root@bogon mianshi]#
- 顺序输出 fruits
import "fmt"
func main() {
fruits := map[string]int{
"oranges": 100,
"apples": 200,
"bananas": 300,
}
for k, v := range fruits {
fmt.Println(k, v)
}
}
测试结果:
[root@bogon mianshi]# go build main.go
[root@bogon mianshi]#
[root@bogon mianshi]#
[root@bogon mianshi]# ./main
oranges 100
apples 200
bananas 300
[root@bogon mianshi]#