金山实习笔试题(湖南大学站)略解,有源码有真相

时间:2014.04.13

地点:~~~

-------------------------------------------------------------------------

一、前述

  好几天前,金山来著名的千年学府招实习生,当天有事没去,后来在QQ空间发现有人传了张照片,比较模糊,不过凑近电脑硬是睁开眼睛还看得清,自己逐个实现了下,按传说中的Google规范。但讲究规范很费神,可能还有漏洞不完善,如有问题,欢迎大家拍砖和指教,共同进步。(默默地感谢下传照片的人)

-------------------------------------------------------------------------

二、题目一:容器类实现

  要求实现一个整数的MyVector,要有基本功能,什么添加元素,删除元素(按给定索引删除),获得容器当前大小和容器可存储大小,构造函数,复制构造函数,析构函数,=运算符,[ ]运算符重载,内存动态扩展(不得使用不连续内存,换句话说就是不得使用链表实现,当然内存可扩展亦不能使用数组实现),总的来说内容很多但很基础,具体题目我也记不清了,但大概就是这个样。

第一步:

设计一个类,好比设计一个楼房,不是看到问题就写代码,而是先画工程图纸,哪里是电梯,哪里装消防栓等,这里的图纸可先早草纸上勾画,然后写正式的类声明,即头文件,头文件就相当于施工的图纸,包括各种成员函数,各种成员变量。头文件如下(按理来说,标准的做法是头文件前一部分是文档说明,什么前置条件,后置条件,库的使用,函数功能等等,但懒得写了,但应该要成为一种好的习惯,好的代码不是很多的注释,代码最好本身就是注释,并有完整的文档可供查阅):

#ifndef MY_VECTOR_H
#define MY_VECTOR_H
#include<initializer_list>
// FILE. MyVector.h
//
// CONSTRUCTOR for the MyVector class:
// MyVector() = default;
// MyVector(std::initializer_list<int> args);
// MyVector(const MyVector&);
// MyVector& operator=(const MyVector&);
//
class MyVector
{
public:
	//CONSTRUCTOR 
	MyVector();
	MyVector(int n,int data);
	MyVector(std::initializer_list<int> args);
	MyVector(const MyVector& );
	
	~MyVector();
	//MODIFICATION MEMBER FUNCTIONS
	void push_back(int element);
	void erase(int index);
	MyVector& operator=(const MyVector& );
	int& operator[](int index){ return start_[index]; };


	//CONSTANT MEMBER FUNCTION
	int size() const{ return size_; }
	int capacity() const{ return capacity_; }
	const int& operator[](int index) const{ return *(start_ + index); }
private:
	//Remalloc memory
	void Reserve(int capacity);
	//Private member
	int size_;
	int capacity_;
	int* start_;
	int* finish_;
	int* end_of_storage_;
};
#endif

注意在写头文件时,头文件保护符的应用应是习惯,另外诸如函数该不该内联的情况,一般来说,函数只有一行时应该内联,还有要考虑的情况,该不该提供普通版和常量版两个版本的成员函数呢,一般说来当函数返回类型引用或指针时应该提供两个版本,另外构造函数到底要有几个,该不该使用默认构造函数,亦有韵味。


第二部:类的实现

  类的声明与实现一般分离,从构造函数说起,首先常规的构造函数肯定是要有的,当然该类的实现涉及对象的拷贝,而已要深拷贝,因为对象的创建涉及到指针和计数,其次我还写了一个统一初始化列表对对象进行初始化,这个构造函数叫做统一初始化构造函数,另外还有内存的分配,当容器容量接近封顶时,我们要重新给对象分配更大的内存,然而要求是必须使用连续的块,如此你不能依靠链表实现,然而还要求内存可扩展,所以你也不能用数组实现,还有就是涉及到下标操作时要对下标进行断言。等等,还有好多小细节,代码实现如下:

#include"my_vector.h"
#include<cassert>
#include<initializer_list>
//CONSTRUCTOR
//Default constructor
MyVector::MyVector() :size_(0), capacity_(2), start_(0), 
          finish_(0), end_of_storage_(0){}

//Use given data and number initialize vector
MyVector::MyVector(int n, int data): size_(0), capacity_(2 * n)
{
	start_ = new int[capacity_];
	finish_ = start_;
	end_of_storage_ = start_ + capacity_;
	while (n--)
		push_back(data);
}
//Initialization constructor  (C++11 Style)
MyVector::MyVector(std::initializer_list<int> args) :size_(0), capacity_(2 * args.size())
{
	start_ = new int[capacity_];
	finish_ = start_;
	end_of_storage_ = start_ + capacity_;
	for (auto data : args)
		push_back(data);
}
//Copy constructor  (must implemenlization deep copy
MyVector::MyVector(const MyVector& my_vector) :size_(0), capacity_(my_vector.capacity_)
{
	start_ = new int[capacity_];
	finish_ = start_;
	end_of_storage_ = start_ + capacity_;
	for (int index = 0; index < my_vector.size(); ++index)
	{
		int a = my_vector[index];
		push_back(my_vector[index]);
	}
}

//MODIFICATION MENBER FUNCTION
//Add element to the vector
void MyVector::push_back(int element)
{
	if (finish_ ==end_of_storage_)
		Reserve(2*capacity_);
	*finish_++ = element;
	++size_;
}
//According given index erase one element
void MyVector::erase(int erase_index)
{
	assert(erase_index < size_ &&erase_index >= 0);
	for (int index = erase_index; index < size_; ++index)
		start_[index] = start_[index+1];
	--size_;
}
//Assign operator
MyVector& MyVector::operator = (const MyVector& my_vector)
{
	if (this == &my_vector)
		return *this;
	delete[] start_;
	start_ = new int[my_vector.capacity_];
	finish_ = start_ + my_vector.size_;
	capacity_ = my_vector.capacity_;
	end_of_storage_ = start_ + capacity_;
	for (int index = 0; index < size_; ++index)
		push_back(my_vector[index]);
	return *this;
}
int& MyVector::operator[](int index)
{ 
	assert(index < size_ &&index>=0);
	return start_[index]; 
}
const int& MyVector::operator[](int index) const
{ 
	assert(index < size_ &&index >= 0);
	return start_[index];
}

void MyVector::Reserve(int capacity=2)
{
	int* memory_ = new int[capacity];
	for (int index = 0; index < size_; ++index)
		memory_ [index] = start_[index];
	delete[] start_;
	start_ = memory_;
	finish_ = memory_ + size_;
	end_of_storage_ = memory_ + capacity;
	capacity_ = capacity;
}
MyVector::~MyVector()
{
	if (start_ != nullptr)
	{
		delete[] start_;
		start_ = nullptr;
	}
}

就近说一个点,上面的析构函数很有讲究,start_delete后这块内存就无效可重新用于分配了,但为了让他不成为野指针而被错误使用,我们还把它赋值为nullptr。

第三步:测试代码

对已有的设计进行各种测试,

#include"my_vector.h"
#include<iostream>
using namespace std;
int main()
{
	MyVector my_vector1;
	for (size_t i = 0; i < 20; i++)
		my_vector1.push_back(i);
	cout << "my_vector1:" << endl;
	for (size_t i = 0; i < 20; i++)
		cout<< my_vector1[i] << " ";
	cout << endl << "my_vector1's current size: " << my_vector1.size() << endl;
	cout << "my_vector1's current capacity: " << my_vector1.capacity() << endl;

	MyVector my_vector2(5, 10);
	my_vector2.push_back(11);
	my_vector2.push_back(12);
	my_vector2.push_back(13);
	my_vector2.push_back(14);
	my_vector2.push_back(15);
	my_vector2.push_back(16);
	cout <<endl<< "my_vector2:" << endl;
	for (size_t i = 0; i <= 10; i++)
		cout << my_vector2[i] << " ";
	cout << endl << "my_vector2's current size: " << my_vector2.size() << endl;
	cout << "my_vector2's current capacity: " << my_vector2.capacity() << endl;
	
	MyVector my_vector3 = {0, 1, 2, 3, 4, 5, 6, 7 };
	cout << endl<< "my_vector3:" << endl;
	for (size_t i = 0; i <8; i++)
		cout << my_vector3[i] << " ";
	cout << endl << "my_vector3's current size: " << my_vector3.size() << endl;
	cout << "my_vector3's current capacity: " << my_vector3.capacity() << endl;

	cout << endl << "my_vector3 erase one element: " << endl;
	my_vector3.erase(4);
	for (size_t i = 0; i <7; i++)
		cout << my_vector3[i] << " ";
	cout << endl << "my_vector5's current size: " << my_vector3.size() << endl;
	cout << "my_vector5's current capacity: " << my_vector3.capacity() << endl;
	
	MyVector my_vector4(my_vector3);
	cout << endl << "my_vector4:" << endl;
	for (size_t i = 0; i <7; i++)
		cout << my_vector3[i] << " ";
	cout << endl << "my_vector4's current size: " << my_vector4.size() << endl;
	cout << "my_vector4's current capacity: " << my_vector4.capacity() << endl;
	
	MyVector my_vector5=my_vector3;
	cout << endl << "my_vector5:" << endl;
	for (size_t i = 0; i <7; i++)
		cout << my_vector5[i] << " ";
	cout << endl << "my_vector5's current size: " << my_vector5.size() << endl;
	cout << "my_vector5's current capacity: " << my_vector5.capacity() << endl;
	return 0;
}

-------------------------------------------------------------------------

三、题目二:字符串排序

给出一系列的字符串要求用快速排序给出排序结果,比如“what are you dong"应该输出"are doing what you" 。当然这里要求是只实现函数,不得使用库函数,不得使用库函数的意思是说什么strcpy这里都不许用。因为题目要求是只实现函数部分,所以在这里给出得源码重点是QuickSort函数的实现,对输入字符串的统计我就没统计了,而是要求给定一个具体的数,快速排序算法的实现是按照填补挖坑的办法实现,快速排序的具体实现方式有很多种。完整代码如下:

#include<iostream>
#include<string>
using namespace std;
int Compare(char* str_first, char* str_second);
char** StringSerial(size_t* word_count)
{
	size_t  N;
	cout << "Please input string's number: " << endl;
	cin >> N;
	*word_count = N;
	cout << "Please input a serial of test string: " << endl;
	char** string_serial = new char*[N];
	for (size_t str_index = 0; str_index < N; ++str_index)
	{
		string_serial[str_index] = new char[N];
		cin >> string_serial[str_index];
	}
	return string_serial;
}
void QuickSort(char** string_serial,int start_index,int end_index)
{
	if (start_index <end_index)
	{
		char* p_element = string_serial[start_index];
		int tail = end_index, header = start_index;
		while (header < tail)
		{
			for (; header<tail; --tail)
			{
				if (Compare(string_serial[tail], p_element)!=1)
				{
					string_serial[header++] = string_serial[tail];
					break;
				}
			}
			for (; header < tail; ++header)
			{
				if (Compare(p_element, string_serial[header]) == -1)
				{
					string_serial[tail--] = string_serial[header];
					break;
				}
			}
		}
		string_serial[tail] = p_element;
		QuickSort(string_serial, start_index, header-1);
		QuickSort(string_serial, header + 1, end_index);
	}
}
int Compare(char* str_first, char* str_second)
{
	char* p_first = str_first;
	char* p_second = str_second;
	while ( *(p_first)!= '\0' || (*p_second) != '\0')
	{
		if ( ( (*p_first) != '\0' && (*p_second) == '\0') || (*p_first) > (*p_second))
			return 1;
		else if (((*p_second) != '\0' && (*p_first) == '\0') || (*p_first) < (*p_second))
			return -1;
		else
		{
			++p_first;
			++p_second;
		}
	}
	return 0;
}
int main()
{
	size_t count;
	char** serial_string = StringSerial(&count);
	QuickSort(serial_string,0,count-1);
	for (size_t i = 0; i < count; ++i)
		cout << serial_string[i] << " "<<endl;
	return EXIT_SUCCESS;
}
-------------------------------------------------------------------------

四、题目三:螺旋矩阵问题

给定一个矩阵,要求按逆时针旋转输出,矩阵不一定是方正。没有用递归实现,但有一个地方我觉得还是设计得很巧妙,就是每条边的输出时,我并没有遇到每条边全部输出完,而是留出了一个数,这样可保证在重现计算新坐标时按对角线坐标计算很方便,并且保持了一致性,不容易出错。

#include<iostream>
using namespace std;
int** CreateMatrix(size_t rows, size_t colums);
//Precondition:
//Postcondition: According the given elements create a rows*colums matrix.
void SpiralPrint(int**p_martix, size_t rows, size_t colums);
//Precondition:
//Postcondition: Print the martrix elements spirally.
int main()
{
	size_t rows, colums;
	cout << "Please input the matrix's rows and colums number: " << endl;
	cin >> rows >> colums;
	cout << "Please input the matrix's element: " << endl;
	int** input_matrix=CreateMatrix(rows, colums);
	cout << "The spiral matrix is: " << endl;
	SpiralPrint(input_matrix,rows,colums);
	cout << endl;
	return EXIT_SUCCESS;
}
int** CreateMatrix(size_t rows, size_t colums)
{
	int**p_martix = new int*[rows];
	for (size_t row_index = 0; row_index < rows; ++row_index)
	{
		p_martix[row_index] = new int[colums];
		for (size_t col_index = 0; col_index < colums; ++col_index)
			cin >> p_martix[row_index][col_index];
	}
	return p_martix;
}
void SpiralPrint(int* *p_martix, size_t rows, size_t colums)
{
	size_t loop = (rows+1) / 2;
	size_t start_index = 0;
	while (loop != 0)
	{
		if (rows == 1)
		{
			for (size_t col_index = start_index; col_index < start_index+colums; ++col_index)
				cout << p_martix[start_index][col_index] << " ";
			break;
		}
		else if (colums==1)
		{
			for (size_t row_index = start_index; row_index < start_index+rows; ++row_index)
				cout << p_martix[row_index][start_index] << " ";
			break;
		}

		for (size_t left_row = start_index; left_row < start_index+rows - 1; ++left_row)
			cout << p_martix[left_row][start_index] << " ";
		for (size_t down_col = start_index; down_col < start_index+colums - 1; ++down_col)
			cout << p_martix[start_index + rows-1][down_col] << " ";
		for (size_t right_row = start_index + rows-1; right_row >start_index; --right_row)
			cout << p_martix[right_row][start_index + colums-1] << " ";
		for (size_t up_col = start_index+colums-1; up_col >start_index; --up_col)
			cout << p_martix[start_index][up_col] << " ";
		++start_index;
		rows -= 2;
		colums -= 2;
		--loop;
	}
}


你可能感兴趣的:(索引,内存,快速排序,设计,可扩展)