嵌入式Linux工程师笔试记录 -- 2020.8.5 (四)

嵌入式Linux工程师笔试记录 – 2020.8.5 (四)
2017年广州代代星笔试题

1.递归方式计算4(1-1/3+1/5-1/7…)的近似值,直到括号最后一项绝对值小于10^-6为止。

解析:此题关键在复杂度的考虑。

方法一(低精度情况下)

/* 递归程序 */
#include <stdio.h>
/* 递归程序 */
double __process( int t ){
        if( t < 0 )
                return 0;
        int tmp = t/2;
        if( tmp%2 == 0 )// 1 5 9 ...
                return __process(t-2) + 1.0/t ;
        else // 3 7 11
                return __process(t-2) - 1.0/t ;
}
double process( long n ){
		if( n%2 == 0 ) // 如果是偶数
			n --;
        return 4*__process(n);
}
int main(){
        long n;
		printf("请输入精度(正整数):");
		scanf("%ld" , &n);
		double t = process( n );
		printf("%.8lf\n",t);
        return 0;
}

结果
在这里插入图片描述

此递归函数很难跑出来(顶多到10^-5),递归层数太多,空间复杂度n,高精度下栈空间有点压力,操作系统也没法做多余的事情。使用二分法递归,空间复杂度降低为logn,可以达到的精度更高。

方法二(要求高精度情况下)

#include <stdio.h>
/* 递归程序 */
/* 采用二分法 */
double __process( long l , long r ){
	if( l == r ) // 结束条件
		if( l/2%2 ) // 3 7 11 
			return -1.0 / l ;
		else // 1 5 9
			return 1.0 / l ;
	long mid = l + (r-l)/2 ; 
	if( mid%2 == 0 )
		mid -- ;
	return __process( l , mid ) + __process( mid+2 , r ); 
}
double process( long n ){

	if( n%2 == 0 ) // 如果是偶数
		n --;
	return 4*__process( 1 , n );
}
int main(){
	long n;
	printf("请输入精度(正整数):");
	scanf("%ld" , &n);
	double t = process( n );
	printf("%.8lf\n",t);
	return 0;
}

结果
在这里插入图片描述
此程序精度达到了10^-8,到-9精度的时候死机了(时间复杂度裂开)。

2. 有N个人围成一圈,顺序排号。从第一个人开始报数(从1-3报数),凡报到3的人退出圈子,问最后留下的人原来排在第几号。(要求用链表实现,代码中有一个实现链表的类,最好有异常处理,写c++代码)

解析约瑟夫环问题,以及要求实现链表类
参考
懒猫老师-C语言-链表作业2:约瑟夫环(三种方法)(猴子选大王)
约瑟夫环的三种解法(循环链表、数组、递归)
代码

#include <iostream>
#include <stdlib.h>

using namespace std;

typedef struct Node{ // 节点
	int data;
	Node *next;
} Node;
class JosephCircle{
private:
	Node * head ; // 头结点
	Node * tail ; // 尾结点
public:
	JosephCircle():tail(NULL),head(NULL){}
	~JosephCircle(){
		// 释放堆空间 
		if(head == tail){
			delete head;
		}else{
			Node *p = head;
			head = head->next ;
			tail = head;
			delete p;
		}
	}
	void additem( int item ){
		// 添加一个结点  头插
		if(tail == NULL){ // 还未有结点
			tail = new Node;
			if(tail==NULL){
				cout << "new Node error" << endl; exit(-1); 
			}
			tail->data = item;
			head = tail;
			tail->next = head;
			
		}else{ // tail != NULL
			Node * new_Node = new Node;
			if( new_Node ==NULL){
				cout << "new Node error" << endl; exit(-1); 
			}
			new_Node->data = item;
			new_Node->next = head;
			head = new_Node;
			tail->next = head;
		}
	}
	int Eliminate( int step ){
		/* 报数到step的时候,移除,返回最后留下的人的排号 */
		Node *p = head;
		while(1){
			if( p->next == p ) // 剩下的最后一人
					break;
			for( int i = 1 ; i < step-1 ; i ++ ){  // 找到报数为step的人前一个人。
				p = p -> next;
			}
			/* 踢出 */
			Node *node = p->next;
			p->next = node->next;
			if( node == tail ) // 如果删了尾部结点
				tail = p;
			if( node == head ){ // 如果删除头结点
				head = p->next;
				tail->next = head;
			}
			delete node;
			p = p->next;	// 下一轮报数
			print();
		}
		return p->data;
	}
	void print(){
		Node *p = head ; 
		while(p!=tail){
			cout << p->data << "->" ;
			p = p->next;
		}
		cout << p->data << endl;
	}
};

int main(){
	int n ;
	cout << "请输入人数:" ;
	cin >> n ;
	JosephCircle list;
	for( int i = 0 ; i < n ; i ++ ){
		list.additem(n-i);
	}
	int result = list.Eliminate(3);
	cout << "结果为:" << result << endl;
	return 0;
}

结果
在这里插入图片描述

2020.8.23添加:v2.0版本

类中主要包含插入和删除操作:

int JosephCircle( int n , int cnt ){
	
	Lst L;				// 初始化一个链表
	for( int i = n ; i > 0 ; i -- )
		L.push_front(i);		// 头插编号,最终为head->1->2->...->n
		Node* p = L.get_head();		// 获取head指针
	int i = 0;
	while( p->next != p ){
		p = p->next;
		if( ++i == cnt ){
			i = 0;
			p = L.erase( p );		// 删除一个编号,返回前一个指针
		}
	}
	int ret = p->value;
	return ret;
}

链表类建立:

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

typedef struct Node{
	int value;
	Node *next;
	Node *pre;
} Node;

class Lst{
public:
	Lst(){
		head = new Node;
		head->next = NULL;		// 指向第一个结点
		head->pre = NULL;		// 指向最后结点
		head->value = 0;
	}
	~Lst(){
		Node *p = head->next;
		while( p != NULL )
			p = erase(p);	// 删除返回前一个指针,删除完最后一个结点,返回NULL
		delete head;
		head = NULL;
	}

	int push_front( int value ){
		
		Node *newNode = new Node;
		if( newNode == NULL )
			return -1;				// 插入错误
		newNode->value = value;
		if( head->next == NULL ){
			head->next = newNode;
			head->pre = newNode;
			newNode->next = newNode;
			newNode->pre = newNode;
		}else{ // head->next != NULL
			newNode->next = head->next;
			head->next->pre = newNode;
			head->next = newNode;
			
			head->pre->next = newNode; // 第一个节点与最后一个结点循环
			newNode->pre = head->pre;
		}

		return  0;
	}
	
	Node * get_head(){
		return head;
	}

	Node * erase( Node * node ){
		
		if( node == NULL )
			return NULL;
			
		Node *p = node;

		p->pre->next = p->next;
		p->next->pre = p->pre;
		
		if( head->next == p ){
			// 第一个结点
			head->next = p->next;
			head->pre->next = p->next;
		}else if( head->pre == p ){
			// 最后一个结点
			head->pre = p->pre;
			head->next->pre = p->pre;
		}
		Node *ret = p->pre;
		if( ret == p )
			return NULL;	// 没有结点了
		
		delete p;
		p->next = NULL;
		p->pre = NULL;
		p = NULL;
		print();
		return ret;
	}
	
	void print(){
		Node *p = head->next;
		cout << "head" ;
		do{
			cout << "->";
			cout << p->value  ;	// 删除返回前一个指针,删除完最后一个结点,返回NULL
			p = p->next;
		}while(p != head->next);
		cout << endl;
	}

private:
	Node * head;
	
};

int JosephCircle( int n , int cnt ){
	
	Lst L;				// 初始化一个链表
	for( int i = n ; i > 0 ; i -- )
		L.push_front(i);		// 头插编号,最终为head->1->2->...->n
		Node* p = L.get_head();		// 获取head指针
	int i = 0;
	while( p->next != p ){
		p = p->next;
		if( ++i == cnt ){
			i = 0;
			p = L.erase( p );		// 删除一个编号,返回前一个指针
		}
	}
	int ret = p->value;
	return ret;
}


int main(){
	
	cout << "结果:" << JosephCircle( 10 , 3 ) << endl;
	return 0;
}

3.编写字符串类String的构造函数、析构函数和赋值函数。

已知 String类的原型如下:

class String {
public:
	String( const char * str = NULL );   	// 普通构造函数
	String( const String &other );   		// 拷贝构造函数
	~String(void);
	String & operate = (const String &other ); 	// 赋值函数
private:
	char * m_data;							// 保存的字符串
}

请编写上述四个函数:

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

class String {
public:
	String( const char * str = NULL );   	// 普通构造函数
	String( const String &other );   		// 拷贝构造函数
	~String(void);
	String & operator = (const String &other ); 	// 赋值函数

	//测试用
	void print(){
		cout << m_data << endl;
	}
private:
	char * m_data;							// 保存的字符串
};

// 普通构造函数
String::String( const char *str ){
	if( str == NULL ){
		m_data = new char[1] ;
		m_data[0] = '\0';
	}
	else{
		m_data = new char[strlen(str)+1];
		strcpy(m_data,str);
	}
}
String::String( const String &other ){
	m_data = new char(strlen(other.m_data)+1);
	strcpy(m_data,other.m_data);
}
String::~String(void){
	if(m_data!=NULL){
		delete [] m_data;
		m_data = NULL;
	}
}

String & String::operator = (const String &other){
	if(this == &other){
		return *this;
	}
	delete[] m_data;
	m_data = new char[strlen(other.m_data)+1];
	strcpy(m_data,other.m_data);
}

int main(){
	String a;
	a = "helloworld";
	a.print();
	String b(a);
	b.print();
	String c;
	c = a;
	c.print();
	
	return 0;
}

结果
在这里插入图片描述

2020.8.23添加:v2.0版本

string的空间连续,并且每次修改长度,都预留传入值的长度的2倍,减少delete和new的操作次数

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

class String {
public:
	String( const char * str = NULL );   	// 普通构造函数
	String( const String &other );   		// 拷贝构造函数
	~String(void);
	String & operator = (const String &other ); 	// 赋值函数

	//测试用
	void print(){
		cout << m_data << endl;
	}
private:
	char * m_data;							// 保存的字符串
};

// 普通构造函数
String::String( const char *str ){
	if( str == NULL ){
		m_data = new char[1] ;
		m_data[0] = '\0';
	}
	else{
		m_data = new char[strlen(str)*2];
		strcpy(m_data,str);
	}
}
String::String( const String &other ){
	m_data = new char(strlen(other.m_data)*2);
	strcpy(m_data,other.m_data);
}
String::~String(void){
	if(m_data!=NULL){
		delete [] m_data;
		m_data = NULL;
	}
}

String & String::operator = (const String &other){
	if(this == &other){
		return *this;
	}
	delete[] m_data;
	m_data = new char[strlen(other.m_data)*2];
	strcpy(m_data,other.m_data);
}

int main(){
	String a;
	a = "helloworld";
	cout << a.c_str() << endl;
	String b(a);
	cout << b.c_str() << endl;
	String c;
	c = a;
	cout << c.c_str() << endl;
	return 0;
}

4.八皇后求解

在这里插入图片描述
每个皇后的同行、同列、同左斜、同右斜都不能有其他皇后。输出所有解。

解析:运用递归求解该题,按行放置皇后,无非就是两个情况, 1 要么检查发现该位置无冲突则放置皇后递归进入下一行放置;2 要么检查发现该位置有冲突/或者当前位置情况已经求解结束,递归进入下一列判断。

所以可以用两重递归解决该问题。

__递归程序( int **map , int cos , int row )
if  列大于棋盘列 
	达到递归结束条件 return 0
if  cos大于棋盘行
	达到递归结束条件,并获得一个解 printMap输出棋盘 , return 0;
if  位置冲突判断 -- 位置合适
	放置皇后
	__递归程序( map , cos+1 , 0 ) ;  进入下一行判断
	恢复原状,从递归回来,说明当前位置的所有情况已经遍历完毕

__递归程序(map , cos , row+1 ) ; 进入下一个位置判断

除此之外就只剩下两个简单的函数需要解决,如何判断该位置是否合适?如何输出棋盘? 总的代码如下:

#include <stdio.h>

// 棋盘大小
#define MAPLENGTH 8 

void printMap( int * map );
int checkplace( int *map , int cos , int row );

/* 递归函数 map为棋盘数组,cos和row为当前位置 */
void __process( int *map , int cos , int row ){
	if(row == MAPLENGTH)
		// 递归结束
		return  ;
	if(cos == MAPLENGTH){
		// 递归结束并获得一解
		printMap( map );
		return  ;
	}
	
	if( checkplace( map , cos , row ) ){
		// 如果位置合适
		map[cos*MAPLENGTH + row] = 1;	// 放置皇后
		__process( map , cos + 1 , 0 );	// 进入下一行判断
		map[cos*MAPLENGTH + row] = 0; 	// 恢复原状
	}
	
	__process( map , cos , row + 1 ) ; // 进入下一个位置判断
	
}
/* 求解函数 n为棋盘大小 */
void process(){
	int map[MAPLENGTH*MAPLENGTH] = {0} ;
	__process( map , 0 , 0 );	//进入递归求解
}

int checkplace( int *map , int cos , int row ){
	
	int i , j ;
	//判断同列是否有皇后
	for( i = 0 ; i < MAPLENGTH ; i ++ ){
		if( i == cos )
			continue;
		if( map[i*MAPLENGTH+row] )
			return 0;	// 冲突
	}
	//判断同列是否有皇后
	for( j = 0 ; j < MAPLENGTH ; j ++ ){
		if( j == row )
			continue;
		if( map[cos*MAPLENGTH+j] )
			return 0;	// 冲突
	}
	//判断同'\'是否有皇后
	i = cos ;
	j = row ;
	while(i&&j){
		i-- ; j--;	//同'\'左上角第一个位置
	}
	for(; i < MAPLENGTH && j < MAPLENGTH ; i ++ , j ++ ){
		if( i == cos )
			continue;
		if( map[i*MAPLENGTH+j] )
			return 0;	// 冲突
	}
	//判断同'/'是否有皇后
	i = cos ;
	j = row ;
	while(i<7&&j){
		i++ ; j--;	//同'/'左下角第一个位置
	}
	for(; i >= 0 && j < MAPLENGTH ; i -- , j ++ ){
		if( i == cos )
			continue;
		if( map[i*MAPLENGTH+j] )
			return 0;	// 冲突
	}
	return 1;	// 无冲突,位置合适
}

void printMap( int * map ){
	static int cnt = 0 ; //计数解个数
	int i , j ;
	printf("第%d个解如下:\n" , ++cnt );
	for( i = 0 ; i < MAPLENGTH ; i ++ ){
		for( j = 0 ; j < MAPLENGTH ; j ++ ){
			if(map[i*MAPLENGTH+j]){
				printf("K");
			}else{
				printf("_");
			}
		}
		printf("\n");
	}
}

int main(){
	
	process();
	return 0;
}

结果
在这里插入图片描述

2020.8.23添加:v2.0版本

直接用一个8*8的数组表示浪费时间,并且每次checkplace都会遍历每个可能(O(n))。
根据懒猫老师的课程,起始可以用一个长度为8的数组表示每个皇后所在列,并且可以用三个数组表示行和斜线上存在皇后与否,使得checkplace判断只需三次(O©)

bool KingCol[8] ; 	// 	row,col处放了皇后 == KingCol[col] = true 
bool KingL[8*2];		//  == KingL[col+row] = true;
bool KingR[8*2];		//  == KingR[col-row+7] = true;

判断语句:

if( !KingCol[col] && !KingL[col+row] && !KingR[col-row+7] ){
		
	// 设置冲突域
	KingCol[col] = true;
	KingL[col+row] = true;
	KingR[col-row+7] = true;
	process( row+1 , 0 );	// 下一行判断
	
	// 恢复原状
	KingCol[col] = false;
	KingL[col+row] = false;
	KingR[col-row+7] = false;
}

完整代码:

#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;


bool KingCol[8] ; 	// 	row,col处放了皇后 == KingCol[col] = true 
bool KingL[8*2];		//  == KingL[col+row] = true;
bool KingR[8*2];		//  == KingR[col-row+7] = true;

int cnt = 0;

void process( int row , int col ){

	if( col == 8 ){
		return ;
	}
	if( row == 8 ){
		cnt++;
		return ;
	}
	if( !KingCol[col] && !KingL[col+row] && !KingR[col-row+7] ){
		
		// 设置冲突域
		KingCol[col] = true;
		KingL[col+row] = true;
		KingR[col-row+7] = true;
		process( row+1 , 0 );	// 下一行判断
		
		// 恢复原状
		KingCol[col] = false;
		KingL[col+row] = false;
		KingR[col-row+7] = false;
	}
	process( row , col+1 );	// 下一列判断
}



int main(){
	
	process(0,0);
	cout << cnt << endl;
	return 0;
}

结果:
输出92

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值