一些经典的面试题,会不断更新滴!
/************************************************************************/
/*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;
}