剑指Offer习题练习

面试题1:赋值运算符函数

/*
	* 面试题一:赋值运算符函数
	* 题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数
	class CMyString
	{
		public:
				CMyString(char* pData = nullptr);
				CMyString(const CMyString& str);
				~CMyString(void);
		private:
				char* m_pData;
	};

	* 注意点:
	* 1、是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用(*this)。
	* 只有返回一个引用,才可以允许连续赋值。否则,如果函数的返回值是void,
	* 则应用该赋值运算符将不能进行连续赋值。假设有3个CMyString的对象:str1、str2和str3,在程序中
	* 用语句str1=str2=str3将不能通过编译。
	* 2、是否把传入的参数的类型声明为常量引用。如果传入的参数不是引用而是实例,那么从形参到实参会
	* 调用一次复制构造函数。把参数声明为引用可以避免这样的无谓消耗,能提高代码的效率。同时,我们在
	* 赋值运算符函数内不会改变传入的实例的状态,因此应该为传入的引用参数加上const关键字。
	* 3、是否释放实例自身已有的内存。如果我们忘记在分配新内存之前释放自身已有的空间,则程序将出现内存泄漏。
	* 4、判断传入的参数和当前的实例(*this)是不是同一个实例。如果是同一个,则不进行赋值操作,直接返回。
	* 如果事先不判断就进行赋值,那么在释放实例自身内存的时候就会导致严重的问题:当*this和传入的参数是同一个实例时
	* 一旦释放了自身的内存,传入的参数的内存也同时被释放了,因此再也找不到需要赋值的内容了。

*/

/*
	经典的解法,适用于初级程序员
*/
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string.h>
#pragma warning(disable:4996)
class CMyString
{
public:
	CMyString(char* pData = nullptr);
	CMyString(const CMyString& str);
	~CMyString(void);

	CMyString& operator=(const CMyString& str);
	void Print();
private:
	char* m_pData;
};

CMyString::CMyString(char* pData)
{
	if (pData == nullptr) {
		m_pData = new char[1];
		m_pData[0] = '\0';
	}
	else {
		int length = strlen(pData);
		m_pData = new char[length + 1];
		strcpy(m_pData, pData);
	}
}

CMyString::CMyString(const CMyString& str)
{
	int length = strlen(str.m_pData);
	m_pData = new char[length + 1];
	strcpy(m_pData, str.m_pData);
}

CMyString::~CMyString()
{
	delete[] m_pData;
}

CMyString& CMyString::operator=(const CMyString &str)
{
	if (this == &str)		// 判断传入的参数和当前的实例(*this)是不是同一个实例
		return *this;
	delete[] m_pData;		// 分配新内存之前释放自身已有的空间
	m_pData = nullptr;
	m_pData = new char[strlen(str.m_pData) + 1];
	strcpy(m_pData, str.m_pData);
	return *this;			

}

// ===================测试代码======================
void CMyString::Print()
{
	std::cout << m_pData << std::endl;
}

void Test1()
{
	/*
		测试用例
		* 把一个CMyString的实例赋值给另外一个实例
	*/
	std::cout << "Test begins:" << std::endl;
	char* text = "Hello world";
	CMyString str1(text);
	CMyString str2 = str1;
	std::cout << "The expected result is:"<< text << "\n";
	std::cout << "The actual result is: " ;
	str2.Print();

}

void Test2()
{
	// 赋值给自己
	std::cout << "赋值给自己" << "\n";
	char* text = "Hello world";
	CMyString str1(text);
	str1 = str1;
	std::cout << "The expected result is:" << text << "\n";
	std::cout << "The actual result is: ";
	str1.Print();
}

void Test3()
{
	// 连续赋值
	std::cout << "Test3 begins:" << "\n";
	char* text = "Hello World";
	CMyString str1(text);
	CMyString str2, str3;
	str3 = str2 = str1;
	std::cout << "The expected result is:" << text << "\n";
	std::cout << "The actual result is: ";
	str2.Print();
	std::cout << std::endl;

	std::cout << "The expected result is:" << text << "\n";
	std::cout << "The actual result is: ";
	str3.Print();
	std::cout << std::endl;

}




int main()
{
	Test1();
	Test2();
	Test3();
	system("pause");
}

面试题2:实现Singleton模式

/** 面试题2:实现Singleton模式
	* 单例模式,即一个类只有一个实例对象。C++一般的方法是将构造函数、拷贝构造函数
	* 以及赋值操作符函数声明为private级别,从而阻止用户实例化一个类。那么,如何才能获得
	* 该类的对象呢?这时,需要类提供一个public&static的方法,通过该方法获得这个类为一个的一个
	* 实例化对象。这就是单例模式基本的一个思想。
	* 单线程环境:
	* 1、饿汉式:即类产生的时候就创建好实例对象,这是一种空间换时间的方式
	* 2、懒汉式:即在需要的时候,才创建对象,这是一种时间换空间的方式

*/

#include<stdio.h>
#include"CSingleton.h"
#include<iostream>
#include<thread>
#include<mutex>
#include<Windows.h>
#include<process.h>
using namespace std;

/**
* 饿汉式的单例实现
*/
class Singleton
{
private:
	Singleton() {
		m_count++;
		cout << "Singleton begin:" << endl;
		Sleep(1000);
		cout << "Singleton end!" << endl;
	}
	static Singleton* single;
public:
	static Singleton *GetSingleton();
	static void print();
	static int m_count;
};

// 饿汉模式的关键:初始化即实例化
Singleton *Singleton::single = new Singleton;
int Singleton::m_count = 0;

Singleton* Singleton::GetSingleton() {
	// 不再需要进行实例化
	return single;
}
void Singleton::print() {
	cout << m_count << endl;
}

// 回调函数
void threadFunc(void *p) {
	DWORD id = GetCurrentThreadId();		//获得线程id
	cout << id << endl;
	Singleton::GetSingleton()->print();		// 构造函数并获得实例,调用静态成员函数
}
int main()
{
	int threadNum = 3;
	HANDLE threadHdl[100];
	// 创建3个线程
	for (int i = 0; i < threadNum; i++) {
		threadHdl[i] = (HANDLE)_beginthread(threadFunc, 0, nullptr);
	}
	// 让主线程等待所有的线程结束后再退出
	for (int i = 0; i < threadNum; i++) {
		WaitForSingleObject(threadHdl[i], INFINITE);
	}
	cout << "main" << endl;				// 验证主进程是否是最后退出
	system("pause");
}
// 饿汉模式
class Singleton
{
private:
	Singleton() {
		cout << "Singleton()" << endl;
	}
	static Singleton* instance;
public:
	static Singleton* GetSingleton() {
		return instance;
	}
	static Singleton* Destory() {
		delete instance;
		instance = NULL;
	}
};
Singleton* Singleton::instance = new Singleton();
int main()
{
	Singleton* sl1 = Singleton::GetSingleton();
	Singleton* sl2 = Singleton::GetSingleton();
	Singleton* sl3 = Singleton::GetSingleton();
	cout << sl1 << endl;
	cout << sl2 << endl;
	cout << sl3 << endl;
	system("pause");
}

// 懒汉模式
class Singleton
{
private:
	Singleton() {
		cout << "Singleton()" << endl;
	}
	static Singleton* instance;
public:
	static Singleton* GetSingleton()
	{
		if (NULL == instance) {
			instance = new Singleton();
			cout << "对象创建成功" << endl;
		}
		else {
			cout << "对象已经创建成功,无须再创建!" << endl;
		}
		return instance;
	}
	static Singleton* Destory() {
		delete instance;
		instance = NULL;
	}
 };
Singleton* Singleton::instance = NULL;
int main()
{
	Singleton* sl1 = Singleton::GetSingleton();
	Singleton* sl2 = Singleton::GetSingleton();
	Singleton* sl3 = Singleton::GetSingleton();
	cout << sl1 << endl;
	cout << sl2 << endl;
	cout << sl3 << endl;
	system("pause");
}

面试题3:数组中的重复的数字

// 面试题3:数组中重复的数字
/** 数组中重复的数字
* 题目一:找出数组中重复的数字
* 在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,
* 但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
* 例如,如果输入长度为7的数组{2, 3, 1, 0, 2, 5, 3},那么对应的输出是重复的数字2或者3
*/
#include<stdio.h>
#include<iostream>
using namespace std;


bool duplicate(int numbers[], int length, int* duplication)
{
	if (numbers == nullptr || length <= 0) {
		return false;
	}
	for (int i = 0; i < length; i++) {
		if (numbers[i] < 0 || numbers[i] > length) {
			return false;
		}
	}
	for (int i = 0; i < length; ++i) {
		while (numbers[i] != i)
		{
			if (numbers[i] == numbers[numbers[i]]) {
				*duplication = numbers[i];
				return true;
			}
			int temp = numbers[i];
			numbers[i] = numbers[temp];
			numbers[temp] = temp;
		}
	}
	return false;
}
// =================测试代码======================
bool contains(int array[], int length, int number)
{
	for (int i = 0; i < length; ++i) {
		if (array[i] = number) {
			return true;
		}
	}
	return false;
}

void test(char* testName, int numbers[], int lengthNumbers, int expected[], int expectedExpected, bool validArgument)
{
	cout << testName << "begins" << endl;
	int duplication;
	bool validInput = duplicate(numbers, lengthNumbers, &duplication);
	if (validArgument == validInput) {
		if (validArgument) {
			if (contains(expected, expectedExpected, duplication))
				cout << "Passed" << endl;
			else
				cout << "Failed" << endl;
		}
		else
		{
			cout << "Passed" << endl;
		}
	}
	else {
		cout << "Failed " << endl;
	}
}
// 重复的数字是数组中最小的数字
void test1()
{
	int numbers[] = { 2, 1, 3, 1, 4 };
	int duplications[] = { 1 };
	test("test", numbers, sizeof(numbers) / sizeof(int), duplications, sizeof(duplications), true);
}

int main()
{
	test1();
	system("pause");
}

面试题4:二维数组中的查找

/** 面试题4:二维数组中的查找
* 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,
* 每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个
* 二维数组和一个整数,判断数组中是否含有该整数。
*/

#include<iostream>
#include<stdio.h>
using namespace std;

bool Find(int* matrix, int rows, int columns, int number)
{
	bool found = false;
	if (matrix != nullptr && rows > 0 && columns > 0)
	{
		int row = 0;
		int column = columns - 1;
		while (row < rows && column >= 0)
		{
			if (matrix[row * columns + column] == number)
			{
				found = true;
				break;
			}
			else if (matrix[row * columns + column] > number)
			{
				--column;
			}
			else
			{
				++row;
			}
		}
	}
	return found;
}
// ================  测试代码==================
void Test(char* testName, int* matrix, int rows, int columns, int number, bool expected)
{
	if (testName != nullptr)
		cout << testName << "begins" << endl;
	bool result = Find(matrix, rows, columns, number);
	if (result == expected)
		cout << "Passed" << endl;
	else
	{
		cout << "Failed" << endl;
	}
}
// 1    2    8    9
// 2	4	 9	  12
// 4	7	 10   13
// 6	8	 11   15
// 要查找的数在数组中
void Test1()
{
	int matrix[][4] = { {1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15} };
	Test("Test1", (int*)matrix, 4, 4, 7, true);
}

int main()
{
	Test1();
	system("pause");
}

面试题5:替换空格

/** 面试题5:替换空格
* 题目:请实现一个函数,把字符串中的每个空格替换成"%20"。
* 例如,输入"We are happy.",则输出"We%20are%20happy."。
*/
#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;

/* length为字符数组str的总容量,大于或等于字符串str的实际长度 */
void ReplaceBlank(char str[], int length)
{
	if (str == nullptr && length <= 0)
		return;

	/* originalLength为字符串的str的实际长度 */
	int originalLength = 0;
	int numberOfBlank = 0;
	int i = 0;
	while (str[i] != '\0')
	{
		++originalLength;
		if (str[i] == ' ')
			++numberOfBlank;
		++i;
	}
	/* newLength为把空格替换成'%20'之后的长度 */
	int newLength = originalLength + numberOfBlank * 2;
	if (newLength > length)
		return;
	int indexOfOriginal = originalLength;
	int indexOfNew = newLength;
	while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
	{
		if (str[indexOfOriginal] == ' ')
		{
			str[indexOfNew--] = '0';
			str[indexOfNew--] = '2';
			str[indexOfNew--] = '%';
		}
		else
		{
			str[indexOfNew--] = str[indexOfOriginal];
		}
		--indexOfOriginal;

	}
}

// 空格在句子中间
void Test1()
{
	const int length = 100;
	char str[length] = "hello world";
	ReplaceBlank(str, 100);
	cout << str << endl;
	system("pause");
}
int main()
{
	Test1();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值