面试题集锦

一些经典的面试题,会不断更新滴!

/************************************************************************/
/*train.h                                                               */
/************************************************************************/

#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

//快速排序
void QuickSort(int data[], int size);
//冒泡排序
void BubbleSort(int data[], int size);
//插入排序
void InsertSort(int data[], int size);
//选择排序
void SelectSort(int data[], int size);
//找出字符串中第一个不重复的字符
int FindFirstNotRepeat(const char *pStr = NULL, int nSize = -1);
//找出字符串中最后一个重复的字符
int FindLastRepeat(const char *pStr = NULL, int nSize= -1);
//找出字符串中第一个不重复的字符
int FirstNoRepeat(const char *pStr = NULL, int nSize = -1);
//找出字符串中第一个不重复的字符
int LastRepeat(const char *pStr = NULL, int nSize = -1);
//字符串拷贝
char* StrCopy(char *Dst, const char *Src);
//字符串长度
int StrLenth(const char *pStr);
//循环右移字符串n位
void LoopRightMove(char *pStr, int nSteps);
//跳台阶算法
int Fibonacci(int n);
//从1....n中随机输出m个不重复的数
void knuth(int n, int m);
//求n以内的质数
void GetPrim(int n);
//以下prim函数的功能是分解质因数(n是质因数,从2开始)
void prim(int m, int n);
//给定一个字符串,求(可重叠k次的)最长重复子串。
void FindLSubStr(char *pStr, int nSize);
//全排列
void Perm(char *pStr, int nSize);
//奇偶排序
void Odd_EvenSort(int data[], int size);
//汉诺塔问题(递归)
void hanoi(int n, char cA, char cB, char cC);
//常量指针与指针常量
void ConstPoint();
//引用数组作为一个名词是不合法的,因为引用型的数组不能赋初始值;
//但是作为一个动宾短语是可以的,因为数组能够被引用;
//数组的引用作为函数的参数时不会被降级为指针。
void Reference();
//数组的大小和长度问题
void ArrRe();

//string类的实现
class String
{
public:
	String(const char *str = NULL);
	String(const String &strOther);
	~String();
	String& operator = (const String &strOther);
	char* StrCopy(const char *Src);
	int StrLenth();
protected:
private:
	char *m_data;
};

//链表模板类的前置声明
template<class T> class NodeList;
//结点模板类
template<class T> class Node
{
	friend NodeList<T>;
public:
	Node(){}
	~Node(){}
	Node(T data, Node<T> *pNext = NULL) :m_data(data), m_pNext(pNext){}
	T GetData() { return m_data; }
	Node<T>* GetNext() { return m_pNext; }
protected:
private:
	T m_data;
	Node<T> *m_pNext;
};

//链表模板类
template<class T> class NodeList
{
public:
	NodeList(Node<T> *pHead = NULL, Node<T> *pTail = NULL) :m_pHead(pHead), m_pTail(pTail){}
	~NodeList(){ Clear(); }
	void Clear();
	void Push_Back(const T &data);
	void Reverse();
	Node<T> *m_pHead;
	Node<T> *m_pTail;
protected:
private:
};

/************************************************************************/
/*链表类模板的实现                                                      */
/************************************************************************/
//清除函数
template<class T>
void NodeList<T>::Clear()
{
	while (m_pHead != NULL)
	{
		Node<T> *pNext = m_pHead->m_pNext;
		delete m_pHead;
		m_pHead = pNext;
	}
	m_pTail = NULL;
}
//链表尾部插入数据
template<class T>
void NodeList<T>::Push_Back(const T &data)
{
	Node<T> *pNode = new Node<T>(data);

	if (m_pHead == NULL)
	{
		m_pHead = pNode;
		m_pTail = pNode;
	}
	else
	{
		m_pTail->m_pNext = pNode;
		m_pTail = pNode;
	}
}
//链表反转
template<class T>
void NodeList<T>::Reverse()
{
	if (m_pHead == NULL)
	{
		return;
	}

	Node<T> *pPrev = m_pHead;
	Node<T> *pCurr = m_pHead->m_pNext;
	while (pCurr != NULL)
	{
		Node<T> *pNext = pCurr->m_pNext;
		pCurr->m_pNext = pPrev;
		pPrev = pCurr;
		pCurr = pNext;
	}

	m_pHead->m_pNext = NULL;
	m_pTail = m_pHead;
	m_pHead = pPrev;
}

//template NodeList<int>;		//模板的显示实例化

/************************************************************************/
/*
模板实例化为类或者函数这个过程是在编译期间完成的,而类实例化为对象是在运行期间完成的。
在C++标准中实际上支持两种编译方式,一种是包含编译式,另一种是分离编译式。
包含编译式是指模板函数的声明和定义都是在同一个文件中,一般来说是一个.h 头文件。
分离编译式则不同,声明和定义分别在不同的文件中,但是在定义之前需要加一个关键字export。
*/
/************************************************************************/

//函数模板
template<class T1, class T2>
void Fun1(T1 a, T2 b)
{
	//
}

//局部特化
template<class T1, const char*>
void Fun1(T1 a, const char *b)
{
	//
}
//模板的参数
template<class T1, int nSize>
void Fun2(T1 a)
{
	int n = nSize;
}
//模板参数可以带缺省值,但是与函数的缺省参数一样,必须靠右。仅允许在类模板上使用默认模板参数。
template<class T1, int nSize = 100>
class A
{
public:
protected:
private:
};

//模板相关
void Fun();
/************************************************************************/
/*train.cpp                                                             */
/************************************************************************/

#include "sort.h"
#include <iostream>
#include <string>
#include <time.h>

using namespace std;

//快速排序实现
void QuickSortImpl(int data[], int left, int right)
{  
	if(left >= right)  
		return;        
	int i = left, j = right;  
	int p = left;   
	int key = data[p];  
	for (i = left, j = right; i < j;)  
	{      
		while (i < p && data[i] <= key)  
		{          
			i++;     
		}       
		if (i < p) 
		{           
			data[p] = data[i];    
			p = i;      
		}      
		while (j > p && data[j] >= key)  
		{         
			j--;       
		}      
		if (j > p) 
		{         
			data[p] = data[j];   
			p = j;   
		}    
	}   
	data[p] = key; 
	QuickSortImpl(data, left, p);  
	QuickSortImpl(data, p+1, right);
}  

//快速排序
void QuickSort(int data[], int size)
{
	QuickSortImpl(data, 0, size-1);
}

//冒泡排序
void BubbleSort(int data[], int size) 
{    
	int i, j;  
	int temp;   
	bool flag;     
	for (i = 0; i < size-1; i++)  
	{     
		flag = true;     
		for (j = 1; j < size-i; j++)    
		{        
			if (data[j] < data[j-1])  
			{            
				temp = data[j];    
				data[j] = data[j-1]; 
				data[j-1] = temp;      
				flag = false;         
			}        
		}       
		if (flag)    
		{          
			break; 
		}  
	} 
} 

//插入排序
void InsertSort(int data[], int size)
{     
	int i, j;   
	int temp;   
	for (i = 0; i < size-1; i++)   
	{       
		temp = data[i+1];  
		for (j = i; j >= 0 && temp < data[j]; j--)     
			data[j+1] = data[j];   
		data[j+1] = temp;  
	}
}  

//选择排序
void SelectSort(int data[], int size)
{  
	int i, j;    
	int temp;    
	int min;     
	for (i = 0; i < size-1; i++)  
	{        
		min = i; 
		for (j = i; j < size; j++)   
		{           
			if (data[j] < data[min])   
			{             
				min = j;    
			}      
		}      
		if (i < min) 
		{          
			temp = data[i]; 
			data[i] = data[min];    
			data[min] = temp;     
		}    
	} 
}

//找出字符串中第一个不重复的字符
int FindFirstNotRepeat(const char *pStr/* = NULL*/, int nSize/* = -1*/)
{
	//若为空字符串就退出
	if (NULL == pStr)
	{
		return -1;
	}
	//若字符串长度参数为-1,以'\0'表示字符串结尾,重新计算长度
	if (-1 == nSize)
	{
		nSize = (int)strlen(pStr);
	}
	//设置字符在字符串中的位置索引
	int nIndex = 0;
	//一个标志,true表示未重复,false表示重复
	bool bFlag;
	//循环查找符合要求的字符
	for (int i = 0; i < nSize; i++)
	{
		nIndex = i;
		bFlag = true;
		for (int j = 0; j < nSize; j++)
		{
			//下标相等表示是同一个数,直接进行下一个字符的比较
			if (i == j)
			{
				continue;
			}
			//如果相等,则说明字符重复
			if (pStr[i] == pStr[j])
			{
				bFlag = false;
				break;
			}
		}
		//如果标志一直是不重复就找到符合要求的字符
		if (bFlag)
		{
			break;
		}
	}
	//如果找不到符合要求的字符,返回-1
	if (bFlag == false)
	{
		nIndex = -1;
	}

	return nIndex;
}

//找出字符串中最后一个重复的字符
int FindLastRepeat(const char *pStr/* = NULL*/, int nSize/* = -1*/)
{
	//若为空字符串就退出
	if (NULL == pStr)
	{
		return -1;
	}
	//若字符串长度参数为-1,以'\0'表示字符串结尾,重新计算长度
	if (-1 == nSize)
	{
		nSize = (int)strlen(pStr);
	}

	//循环查找符合要求的字符
	for (int i = nSize - 1; i >= 0; i--)
	{
		for (int j = 0; j < i; j++)
		{
			if (pStr[i] == pStr[j])
			{
				return i;
			}
		}
	}

	return -1;
}

//找出字符串中第一个不重复的字符
int FirstNoRepeat(const char *pStr/* = NULL*/, int nSize/* = -1*/)
{
	//若为空字符串就退出
	if (NULL == pStr)
	{
		return -1;
	}
	//若字符串长度参数为-1,以'\0'表示字符串结尾,重新计算长度
	if (-1 == nSize)
	{
		nSize = (int)strlen(pStr);
	}

	//因为只有128个字符,所以可以申请整形数组,目的是存取每个字母出现的次数
	int nArr[128] = {0};
	//记录每个字符出现的次数
	for (int i = 0; i < nSize; i++)
	{
		int n = (int)pStr[i];
		nArr[n]++;
	}
	//寻找符合要求的字符的索引
	for (int i = 0; i < nSize; i++)
	{
		int n = (int)pStr[i];
		if (1 == nArr[n])
		{
			return i;
		}
	}

	return -1;
}

//找出字符串中最后一个重复的字符
int LastRepeat(const char *pStr/* = NULL*/, int nSize/* = -1*/)
{
	//若为空字符串就退出
	if (NULL == pStr)
	{
		return -1;
	}
	//若字符串长度参数为-1,以'\0'表示字符串结尾,重新计算长度
	if (-1 == nSize)
	{
		nSize = (int)strlen(pStr);
	}

	//因为只有128个字符,所以可以申请整形数组,目的是存取每个字母出现的次数
	int nArr[128] = {0};
	//记录每个字符出现的次数
	for (int i = 0; i < nSize; i++)
	{
		int n = (int)pStr[i];
		nArr[n]++;
	}
	//寻找符合要求的字符的索引
	for (int i = nSize-1; i >= 0; i--)
	{
		int n = (int)pStr[i];
		if (1 < nArr[n])
		{
			return i;
		}
	}

	return -1;
}

//字符串拷贝
char* StrCopy(char *Dst, const char *Src)
{
	char *Addr = Dst;
	if (NULL != Dst && NULL != Src && Dst != Src)
	{
		while ((*Dst++ = *Src++) != '\0');
	}

	return Addr;
}

//字符串长度
int StrLenth(const char *pStr)
{
	int nLen = 0;
	if (NULL != pStr)
	{
		while (*pStr++ != '\0')
		{
			nLen++;
		}
	}
	return nLen;
}

//循环右移字符串n位
void LoopRightMove(char *pStr, int nSteps)
{
	//如果字符串为空
	if (NULL == pStr)
	{
		return;
	}
	//计算相关数值,如果右移位数为0
	int nLen = StrLenth(pStr);
	nSteps = nSteps % nLen;
	if (0 == nSteps)
	{
		return;
	}
	//动态分配临时内存
	char *strTmp = new char[nLen + nSteps + 1];
	if (NULL == strTmp)
	{
		return;
	}
	::memset(strTmp, 0, nLen + nSteps + 1);
	//
	StrCopy(strTmp, pStr+nLen-nSteps);
	StrCopy(strTmp+nSteps, pStr);
	*(strTmp+nLen) = '\0';
	StrCopy(pStr, strTmp);
	//释放动态分配的内存空间
	delete []strTmp;
	strTmp = NULL;
}

/************************************************************************/
/*跳台阶算法:一个台阶总共有n 级,如果一次可以跳1 级,也可以跳2 级。
求总共有多少总跳法,并分析算法的时间复杂度。
我们把上面的分析用一个公式总结如下:
	/  1				n=1
f(n)=  2				n=2
	\  f(n-1)+(f-2)		n>2										*/
/************************************************************************/
int Fibonacci(int n)
{
	if (n < 3)
	{
		return n;
	}

	int nA1 = 1, nA2 = 2;
	for (int i = 3; i <= n; i++)
	{
		nA2 = nA2 + nA1;
		nA1 = nA2 - nA1;
	}
	return nA2;
}

//从1....n中随机输出m个不重复的数
void knuth(int n, int m)

{
	srand((unsigned int)time(0));

	for (int i = 0; i < n; i++)
	{
		if (rand()%(n-i) < m)
		{
			cout << i << endl;
			m--;
		}
	}
}

//求n以内的质数
void GetPrim(int n)
{
	if (n < 2)
	{
		return;
	}
	int x = 2;
	for (; x < n; x++)
	{
		bool bFlag = true;
		for (int i = 2; i < x/i; i++)
		{
			if (0 == x%i)
			{
				bFlag = false;
				break;
			}
		}
		if (bFlag)
		{
			cout << x << " ";
		}
	}
	cout << endl;
}

//以下prim函数的功能是分解质因数(n是质因数,从2开始)
void prim(int m, int n)
{
	if (m > n)
	{
		while (0 != m%n) n++;
		while (0 == m%n) m /= n;
		cout << n << endl;
		prim(m,n);
	}
}

//给定一个字符串,求(可重叠k次的)最长重复子串。
void FindLSubStr(char *pStr, int nSize)
{
	int nMaxLen = 0;	//最长重复子串的长度
	int nPos = 0;		//最长重复子串的起始位置
	//循环查找最长重复子串
	for (int i = 0; i < nSize-1; i++)
	{
		for (int j = i+1; j < nSize; j++)
		{
			int nLen = 0;
			int m = i, n = j;
			for (; (n < nSize) && (pStr[m++] == pStr[n++]); nLen++);
			if (nLen > nMaxLen)
			{
				nMaxLen = nLen;
				nPos = i;
			}
		}
	}
	//输出最长重复子串
	for (int i = 0; i < nMaxLen; i++)
	{
		cout << pStr[nPos+i] << " ";
	}
	cout << endl;
}

int nCount = 0;
void PermImpl(char pStr[], int nSize, int nPos)
{
	//递归调用的出口
	if (nPos >= nSize)
	{
		nCount++;	//全排列中每个排列的序号
		printf("%-4d:", nCount);
		//输出一个排列
		for (int i = 0; i < nSize; i++)
		{
			cout << pStr[i] << " ";
		}
		cout << endl;
	}

	for (int i = nPos; i < nSize; i++)
	{
		//递归调用函数PermImpl
		PermImpl(pStr, nSize, nPos+1);
		//从nPos位置处开始的所有字符循环左移一位
		char cTemp = pStr[nPos];
		for (int i = nPos; i < nSize-1; i++)
		{
			pStr[i] = pStr[i+1];
		}
		pStr[nSize-1] = cTemp;
	}
}

//全排列
void Perm(char *pStr, int nSize)
{
	nCount = 0;
	PermImpl(pStr, nSize, 0);
}

//奇偶排序
void Odd_EvenSort(int data[], int size)
{
	cout << sizeof data << endl;
	int nKey1 = 0, nKey2 = size-1;
	int i = nKey1, j = nKey2;
	for (; i < j; )
	{
		while ((1 == data[i]%2) && (i < j))
		{
			i++;
		}
		while ((0 == data[j]%2) && (i < j))
		{
			j--;
		}
		if (i < j)
		{
			int temp = data[j];
			data[j] = data[i];
			data[i] = temp;
			i++;
			j--;
		}
	}
	QuickSortImpl(data, 0, i-1);		//需要升序ASC
	QuickSortImpl(data, i, size-1);		//需要降序DESC
}

//汉诺塔问题(递归)
void hanoi(int n, char cA, char cB, char cC)
{
	if (1 == n)
	{
		//从cA直接移动到cC
		printf("%c->%c\n", cA, cC);
	}
	else
	{
		hanoi(n-1, cA, cC, cB);
		//从cA直接移动到cC
		printf("%c->%c\n", cA, cC);
		hanoi(n-1, cB, cA, cC);
	}
}

//常量指针与指针常量
void ConstPoint()
{
	int a = 10;
	//常量指针:指向常量的指针
	const int *p1 = &a;
	*p1++;
	//(*p1)++;
	int const *p2 = &a;
	*p2++;
	//(*p2)++;
	//指针常量:指针本身是个常量
	int* const p3 = &a;
	//*p3++;
	(*p3)++;
	//	int *p4 const = &a;
}

//引用数组作为一个名词是不合法的,因为引用型的数组不能赋初始值;
//但是作为一个动宾短语是可以的,因为数组能够被引用;
//数组的引用作为函数的参数时不会被降级为指针。
void Reference()
{
	int nArr[10] = {0};
	int (&p)[10] = nArr;
	cout << sizeof p << endl;
	cout << sizeof nArr << endl;
	for (int i = 0; i < 10; i++)
	{
		p[i] = i;
	}
	for (int i = 0; i < 10; i++)
	{
		cout << nArr[i] << endl;
	}
}

//数组的大小和长度
void ArrRe()
{
	char a[] = "0123456789";
	cout << sizeof a << endl;
	char b[11] = "0123456789";
	cout << sizeof b << endl;
	//char c[10] = "0123456789";	//数组溢出
	//cout << sizeof c << endl;
	char d[100] = "0123456789";
	cout << sizeof d << endl;
	cout << strlen(d) << endl;
}

/************************************************************************/
/*Strin类的实现                                                         */
/************************************************************************/
//构造函数
String::String(const char *str/* = NULL*/)
{
	if (str == NULL)
	{
		m_data = new char[1];
		m_data = "\0";
	}
	else
	{
		int nLen = this->StrLenth();
		m_data = new char[nLen+1];
		this->StrCopy(str);
	}
}
//拷贝构造函数
String::String(const String &strOther)
{
	int nLen = ::StrLenth(strOther.m_data);
	m_data = new char[nLen+1]();
	::StrCopy(m_data, strOther.m_data);
}
//析构函数
String::~String()
{
	delete []m_data;
}
//赋值函数
String& String::operator = (const String &strOther)
{
	if (this != &strOther)
	{
		delete []m_data;
		int nLen = ::StrLenth(strOther.m_data);
		m_data = new char[nLen+1];
		::StrCopy(m_data, strOther.m_data);
	}

	return *this;
}
//复制(拷贝)函数
char* String::StrCopy(const char *Src)
{
	if (Src != NULL)
	{
		delete []m_data;
		int nLen = ::StrLenth(Src);
		m_data = new char[nLen+1]();
		while ((*m_data++ = *Src++) != '\0');
	}

	return m_data;
}
//计算长度
int String::StrLenth()
{
	int nLen = 0;
	while (*m_data++ != '\0')
	{
		nLen++;
	}

	return nLen;
}
//模板相关
void Fun()
{
	int a = 0, b = 0;
	Fun1(a, b);

	Fun1<double, double> (5.0, 6.0);

	//模板的递归实例化
	A<A<int, 200>, 100> abc;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值