1. 程式人生 > >C++經典面試演算法題

C++經典面試演算法題

#include <assert.h>
#include <string.h>
#include <stack>

//////////////////////////////////////////////////////////////////////////  
// C++ 經典面試演算法題  [7/28/2016 FreeAngel]  

//1.實現strcpy.  
char* MyStrCpy( char *pDest, const char *pSrc )  
{  
	if( nullptr == pDest || nullptr == pSrc )  
	{  
		return nullptr;  
	}  
	if( pDest == pSrc )  
	{  
		return pDest;  
	}  
	char *pIter = pDest;  
	while( ( *pIter++=*pSrc++ ) !='\0' );  
	return pDest;  
}  

//2.實現strcat.  
char* MyStrCat( char *pDest, const char *pSrc )  
{  
	if( nullptr == pDest || nullptr == pSrc )  
	{  
		return nullptr;  
	}  

	char *pIter = pDest + strlen( pDest );  
	while( ( *pIter++=*pSrc++ ) != '\0' );  
	return pDest;  
}  

//3.實現CString字串類預設四個方法  
class MyCString  
{  
public:  

	MyCString( char *pData = nullptr )  
	{  
		if( nullptr == pData )  
		{  
			mpData = new char[ 1 ];  
			assert( nullptr != mpData );  
			*mpData = '\0';  
		}  
		else  
		{  
			mpData = new char[ strlen( pData ) + 1 ];  
			assert( nullptr != mpData );  
			strcpy( mpData, pData );  
		}  
	}  

	MyCString( const MyCString &Other )  
	{  
		mpData = new char[ strlen( Other.mpData ) + 1 ];  
		assert( nullptr != mpData );  
		strcpy( mpData, Other.mpData );  
	}  

	~MyCString()  
	{  
		if( nullptr != mpData )  
		{  
			delete [] mpData;  
			mpData = nullptr;  
		}  
	}  

	const MyCString& operator =( const MyCString &Other )  
	{  
		if( this == &Other )  
		{  
			return *this;  
		}  
		delete [] mpData;  
		mpData = new char[ strlen( Other.mpData ) + 1 ];  
		assert( nullptr != mpData );  
		strcpy( mpData, Other.mpData );  
		return *this;  
	}  

private:  

	char *mpData;  
};  

//4.不使用第三個變數交換兩個數的值  
void SwapA( int &A, int &B )  
{  
	if( A == B )  
	{  
		return;  
	}  
	A = A + B;  
	B = A - B;  
	A = A - B;  
}  
void SwapB( unsigned int &A, unsigned int &B )  
{  
	if( A == B )  
	{  
		return;  
	}
	A = A ^ B;  
	B = A ^ B;  
	A = A ^ B;  
}  

//5.C語言中字串轉數字的方法是什麼( atoi ),請實現它  
int Myatoi( const char *pString )  
{  
	assert( nullptr != pString );  
	const int Len = strlen( pString );  
	int Value = 0;  
	int Times = 1;  
	for( int i = Len -1; i >= 0; --i, Times *= 10 )  
	{  
		Value += ( pString[ i ] - '0' ) * Times;  
	}  
	return Value;  
}  

//6.實現一個將字串逆序的方法  
char* MyInverted( char *pDest )  
{  
	assert( nullptr != pDest );  
	const int Len = strlen( pDest );  
	char T = 0;  
	for( int i = 0; i < Len / 2; ++i )  
	{  
		T = pDest[ i ];  
		pDest[ i ] = pDest[ Len - i - 1 ];  
		pDest[ Len - i -1 ] = T;  
	}  
	return pDest;  
}  

//7.實現一個將字串中所有字母轉換為大寫的方法  
char* MyUpper( char *pDest )  
{  
	assert( nullptr != pDest );  
	for( char *i = pDest; *i != '\0'; ++i )  
	{  
		if( *i < 'a' || *i > 'z' )  
		{  
			continue;  
		}  
		*i -= 'a' - 'A';  
	}  
	return pDest;  
}  

//8.已知一個數組已經降序排序請用二分查字法找到其中的某個元素找到返回索引否則返回-1  
int BinarySearch( int *pArray, int Count, int Value )  
{  
	assert( nullptr != pArray );  
	int Left = 0;  
	int Right = Count -1;  
	int Mid = 0;  
	while( Left <= Right )  
	{  
		Mid = ( Left + Right ) / 2;  
		if( Value < pArray[ Mid ] )  
		{  
			Right = Mid - 1;  
		}  
		else if( Value > pArray[ Mid ] )  
		{  
			Left = Mid + 1;  
		}  
		else  
		{  
			return Mid;  
		}  
	}  
	return -1;  
}  

struct Node  
{  
	Node *mpNext;  
	int mData;  
};
//9.刪除連結串列中值為Value的所有元素( [Head]->[node1]->[node2]->...[noden] )
void DeleteFromList( Node *pHead, int Value )
{
	Node *pPrev = pHead;
	Node *pNext = pHead->mpNext;
	while( nullptr != pNext )
	{
		if( pNext->mData != Value )
		{
			pPrev = pNext;
			pNext = pNext->mpNext;
		}
		else
		{
			pPrev->mpNext = pNext->mpNext;
			delete pNext;
			pNext = pPrev->mpNext;
		}
	}
}  

//10.在連結串列Index位置插入新的值為Value的元素  
void InsertFromList( Node *pHead, int Index, int Value )  
{
	Node *pIter = pHead;
	for( int i = 0; i < Index && nullptr != pIter; ++i, pIter = pIter->mpNext );
	assert( nullptr != pIter );
	Node *pNew = new Node;
	pNew->mData = Value;
	pNew->mpNext = pIter->mpNext;
	pIter->mpNext = pNew;
}  

//11.將連結串列逆序  
Node* InvertedFromList( Node *pHead )  
{  
	//A->B->C
	Node *pPrev = pHead;            //A
	Node *pNext = pHead->mpNext;        //B
	Node *pNextNext = nullptr;        //C
	while( nullptr != pNext )  
	{
		pNextNext = pNext->mpNext;    //C = B->C
		pNext->mpNext = pPrev;        //B->A

		pPrev = pNext;                //A = B
		pNext = pNextNext;            //B = C
	}
	pHead->mpNext = nullptr;//C->B->A->null
	return pPrev;            //return C( new head )
}  

//12.判斷X年X月X日是這年的第幾天  
int GetDay( int Year, int Month, int Day )
{  
	int MonthDays[ 13 ] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };  

	if( ( Year % 4 == 0 && Year % 100 != 0 ) || ( Year % 400 == 0 ) )  
	{  
		++MonthDays[ 2 ];  
	}  

	int Days = 0;  
	for( int i = 1; i < Month; ++i )  
	{  
		Days += MonthDays[ i ];  
	}  
	Days += Day;  

	return Days;  
}
//13.求斐波拉契數列第N項
int GetFibonacci1( int N )
{
	if( 1 == N || 2 == N )
	{
		return 1;
	}
	if( 3 == N )
	{
		return 2;
	}
	int A = 2;
	int B = 3;
	int C = 5;
	for( int i = 0; i < N - 4; ++i )
	{
		C = A + B;
		A = B;
		B = C;
	}
	return C;
}

//14.遞迴求斐波拉契數列數列第N項
int GetFibonacci2( int N )
{
	if( 1 == N || 2 == N )
	{
		return 1;
	}
	return GetFibonacci2( N - 1 ) + GetFibonacci2( N - 2 );
}
//15.實現一個產生[N-M]區間數字的隨機方法
int GetRandomRange( int N, int M )
{
	if( N == M )
	{
		return N;
	}
	if( N > M )
	{
		N = N + M;
		M = N - M;
		N = N - M;
	}
	return N + ( rand() % ( M - N + 1 ) );
}

//16.實現一個產生[0~1]之間的隨機浮點數
double GetRandomRange()
{
	return rand() / static_cast< double >( RAND_MAX );
}
//17.實現一個打印出1-1000之間的所有素數的方法
void PrintfPrime()
{
	//1不是素數
	//2是最小非奇數素數
	//直接從3開始
	printf( "2\n" );
	bool b = false;
	for( int i = 3; i <= 1000; ++i )
	{
		b = true;
		for( int j = 2; j <= i / 2; ++j )
		{
			if( i % j == 0 )
			{
				b = false;
				break;
			}
		}
		if( b )
		{
			printf( "%d\n", i );
		}
	}
}

//18.已知Z = X + Y 其中 Z, X, Y 均為無符號int型 定義一個巨集判斷Z是否已經越界
#define IS_OVER_FLOW( Z, X, Y ) ( Z < ( ( X ) < ( Y ) ? ( Y ) : ( X ) ) )

//19.請用棧實現佇列
int QueuePop( std::stack< int > &StackA )
{
	std::stack< int > StackB;
	while( false == StackA.empty() )
	{
		StackB.push( StackA.top() );
		StackA.pop();
	}

	const int top = StackB.top();
	StackB.pop();

	while( false == StackB.empty() )
	{
		StackA.push( StackB.top() );
		StackB.pop();
	}
	return top;
}

//20.已知X班X成績0-100分編寫一個方法實現0-59列印不合格,60-69打印合格,70-79列印良好,80-100列印優秀
//不能使用if,:?,switch
void PrintScore( int Score )
{
	assert( Score >= 0 && Score <= 100 );
	const char *pString[] =
	{ 
		"不合格",
		"不合格",
		"不合格",
		"不合格",
		"不合格",
		"不合格",
		"合格",
		"良好",
		"優秀",
		"優秀",
		"優秀",
	};
	printf( "%s\n", pString[ Score / 10 ] );
}
//21.實現strncpy
char *Mystrncpy( char *pDest, const char *pSrc, int Count )
{
	assert( NULL != pDest && NULL != pSrc );
	if( pDest == pSrc )
	{
		return pDest;
	}
	if( Count <= 0 )
	{
		return pDest;
	}
	char *pStart = pDest;
	while( ( Count-- ) > 0 && ( *pStart++=*pSrc++ ) );
	*pStart = '\0';
	return pDest;
} 
//22.C語言中數字轉字串的方法是什麼?(itoa)請實現他
char* Myitoa( char *pDest, int val, int radix )
{
	assert( NULL != pDest );
	assert( radix > 1 );
	const bool IsMinu = val < 0;
	char buffer[ 16 ] = {};
	int count = 0;

	do
	{
		buffer[ count++ ] = abs(val) % radix;
		val /= radix;
	}
	while( val );


	if( IsMinu )
	{
		pDest[ 0 ] = '-';
		for( int i = 0; i < count; ++i )
		{
			pDest[ i + 1 ] = '0' + buffer[ count - i - 1 ];
		}
		pDest[ count + 1 ] = '\0';
	}
	else
	{
		for( int i = 0; i < count; ++i )
		{
			pDest[ i ] = '0' + buffer[ count - i - 1 ];
		}
		pDest[ count ] = '\0';
	}
	return pDest;
}
//23.如何判斷連結串列是否有環
bool IsLoop( Node *pHead )
{
	//[H->A->B->C->A]
	assert( NULL != pHead );
	Node *pNext = pHead->mpNext;
	Node *pNextNext = pHead->mpNext;
	while( NULL != pNext && NULL != pNextNext->mpNext )
	{
		pNext = pNext->mpNext;//[ B、C、A ]
		pNextNext = pNextNext->mpNext->mpNext;//[C、B、A]
		if( pNext == pNextNext )
		{
			return true;
		}
	}
	return false;
}
//24.統計出一個字串每種字母出現的次數要求時間複雜度為O(n)
void CountLetter( const char *pSrc )
{
	int count[ 256 ] = {};
	for( ; *pSrc !='\0'; ++pSrc )
	{
		const char &c = *pSrc;
		if( ( c < 'A' || c > 'z') && ( c < 'a' || c > 'z' ) )
		{
			continue;
		}
		++count[ c ];
	}
} 
//25.選擇排序的思想是什麼?( 每次找到最大或最小的值放在陣列的低位上 )請實現它
void SelectSort( int *pArray, int count )
{
	for( int i = 0; i < count; ++i )
	{
		//預設低位元素最小
		int MinValue = pArray[ i ];
		//預設儲存低位元素的索引
		int MinIndex = i;
		//除開第一個元素找是否還有比它還小的元素( 升序 )
		for( int j = i + 1; j < count; ++j )
		{
			//發現找到比它還小的元素重新賦值和儲存索引
			if( pArray[ j ] < MinValue )
			{
				MinValue = pArray[ j ];
				MinIndex = j;
			}
		}
		//將找到最小元素放在陣列低位上面
		const int Temp = pArray[ i ];
		pArray[ i ] = MinValue;
		pArray[ MinIndex ] = Temp;
	}
}

//26.氣泡排序的思想是什麼?(升序排序中越小的數往低位走,越大的數往高位走,每次與相鄰元素比較導致的特點)請實現它
void BubbleSort( int *pArray, int count )
{
	//eg.[6][8][8][0][9][1]
	//i = 0,j < 5    [6][8][0][8][1][9]
	//i = 1,j < 4    [6][0][8][1][8][9]
	//i = 2,j < 3    [0][6][1][8][8][9]
	//i = 3,j < 2    [0][1][6][8][8][9]

	//到此為止已經排序OK了
	//i = 4,j < 1    [0][1][6][8][8][9]
	//i = 5,j < 0    [0][1][6][8][8][9]
	for( int i = 0; i < count; ++i )
	{
		for( int j = 0; j < count - i - 1; ++j )
		{
			if( pArray[ j ] > pArray[ j + 1 ] )
			{
				const int Temp = pArray[ j ];
				pArray[ j ] = pArray[ j + 1 ];
				pArray[ j + 1 ] = Temp;
			}
		}
	}
}

//27.已知兩個陣列有序實現一個方法將他們合併後任然有序
void MergeSort( int *pMerge, int *p1, int p1len, int *p2, int p2len )
{
	assert( nullptr != pMerge && nullptr != p1 && nullptr != p2 );
	int i = 0;
	int j = 0;
	int k = 0;
	while( i < p1len && j < p2len )
	{
		if( p1[ i ] < p2[ j ] )
		{
			pMerge[ k ] = p1[ i ];
			++k;
			++i;
		}
		else
		{
			pMerge[ k ] = p2[ j ];
			++k;
			++j;
		}
	}
	while( i < p1len )
	{
		pMerge[ k ] = p1[ i ];
		++k;
		++i;
	}
	while( j < p2len )
	{
		pMerge[ k ] = p2[ j ];
		++k;
		++j;
	}
}

//28.實現一個演算法找到陣列中第二大的數
int FindSec( int *p, int len )
{
    assert( nullptr != p );
    int maxv = p[ 0 ];
    int secv = p[ 0 ];
    for( int i = 1; i < len; ++i )
    {
        if( maxv < p[ i ] )
        {
            secv = maxv;
            maxv = p[ i ];
        }
    }
    return secv;
}