1.模拟实现 strstr
char* MyStrstr( const char* str1, const char* str2 ){
assert( NULL != str1 && NULL != str2 );
while ('\0' != *str1){
const char* p1 = str1;
const char* p2 = str2;
while (('\0' != *p1) && ('\0' != *p2) && (*p1 == *p2)){
++p1;
++p2;
}
if ('\0' == *p2)
return str1;
++str1;
}
return NULL;
}
2.模拟实现 strcpy
char* MyStrcpy(char* dest, const char* src){
assert( NULL != dest && NULL != src );
char* pAddress = dest;
while ('\0' != (*dest++ = *src++))
;
return pAddress;
}
3.编写类String的构造函数、析构函数和赋值函数,已知类String的原型为:
class String{
public:
String( const char* str = NULL ); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
String & operator =(const String &other); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
String::String( const char* str ){
if (NULL==str){
m_data = new char[1]; // 对空字符串自动申请存放结束标志'\0'的空间
*m_data = '\0';
}
else{
int length = strlen(str);
m_data = new char[length+1];
strcpy(m_data, str);
}
}
// String的析构函数
String::~String( void ){
delete [] m_data; // 或delete m_data;
}
// 拷贝构造函数
// 输入参数为const型
String::String( const String& other ){
int length = strlen( other.m_data );
m_data = new char[length+1];
strcpy( m_data, other.m_data );
}
// 赋值函数
// 输入参数为const型
MyString& MyString::operator=( const MyString& str ){
// 检查自赋值
if ( &str != this ){
MyString strTemp( str );
char* pTemp = strTemp.m_pData;
strTemp.m_pData = m_pData;
m_pData = pTemp;
}
// 返回本对象的引用
return *this;
}
当类中包括指针类成员变量时,一定要重载其拷贝构造函数、赋值函数和析构函数
如果出函数作用域后还存在则可以返回引用, 不存在则不能返回引用,要返回临时对象
4.宏函数 --> 交换两个数
#define SWAP( a, b ) \
do { \
(a) = ((a)^(b)); \
(b) = ((a)^(b)); \
(a) = ((a)^(b)); \
}while (0)
5.模拟实现 strncpy
char* MyStrncpy( char* dest, const char* src, size_t len ){
assert( NULL != dest && NULL != src );
char* ret = dest;
while (0 != len--){
if (0 != (*dest = *src)){
++dest;
++src;
}
}
if (len > 0)
while (len--)
*dest++ = '\0';
return ret;
}
在安全性方面,显然strncpy要比strcpy安全得多,strcpy无法控制拷贝的长度,不小心就会出现dest的大小无法容纳src的情况,就会出现越界的问题,程序就会崩溃。而strncpy就控制了拷贝的字符数避免了这类问题,但是要注意的是dest依然要注意要有足够的空间存放src,而且src 和 dest 所指的内存区域不能重叠
6.获取一个数二进制序列的奇数位和偶数位
int a[32];
for (int i = 0; i < 32; ++i){
a[i] = data % 2;
data /= 2;
}
// 偶数
for (int i = 1; i <= 31; i += 2)
cout << arr[i];
// 奇数
for (int i = 0; i <= 20; i += 2)
cout << arr[i];
7.请写一个模板类,来求两个数中的最大值
注意:求两个"数"的最大值,若两个"数"不是内置类型,而是自定义类型比较大小。则1.看原自定义类型是否重载operator <( )运算符 2.仿函数
template <typename T>
class MaxNumber{
public:
MaxNumber( )
: _a( a )
, _b( b )
{}
T Max( ){
return _a > _b ? _a : _b;
}
private:
T _a;
T _b;
};
int main( ){
int a;
int b;
cin >> a >> b;
MaxNumber<int> m( a, b );
m.Max( );
return 0;
}
8.写一个函数来判断一个字符串是否是对称的
bool Fun( const char* str ){
bool ret = true;
if (NULL == str || ('\0' == *str))
return ret;
char* pBegin = str;
char* pEnd = str + strlen(str) - 1;
// 注意此处不能用 pBegin != pEnd 判断. 想想字符串为偶数个字符的情形(不包括'\0'),是否两个指针刚好错过了.
while (pBegin < pEnd){
if (*pBegin == *pEnd){
++pBegin;
--pEnd;
}
else{
ret = false;
break;
}
}
return ret;
}
9.二分查找的算法
int BinarySearch( int* arr, int len, int key ){
assert( NULL != arr && len > 0 );
int left = 0;
int right = len - 1;
int mid = 0;
while (left<=right){
mid = left + ( (right-left)>>1 );// 不直接用 (left+right)/2 是 防止越界 和 提高效率
if (arr[mid] < key)
left = mid + 1;
else if (arr[mid] > key)
right = mid - 1;
else
return mid;
}
return -1;
}
right = n - 1 => while (left <= right) (利用只有一个元素时情景去想, 如果是 left(0) < rightr(1 - 1 == 0) 循环根本进不去。 所以是<=) => right = middle - 1(middle索引的元素已经被判断,又因为是 left <= right, 所以 right = mid - 1 如果是 right = mid, 这mid索引这个位置元素又会在下次循环被遍历一次);
right = n => while (left < right)(数组只有一个元素 0 < 1 --> 循环进去一次,<=循环进去两次) => right = middle(middle已经被遍历, 又因为left < right, 若right = middle - 1则middle - 1那个元素被略过, 而right = middle -> left < right --> middle不会被重复遍历,middle - 1的元素也不会被略过);
middle = ((left+right) >> 1); 这样的话 left 与 right 的值比较大的时候,其和可能溢出。 --> middle = left + ( (right - left) >> 1 )
10.快速排序
template <typename T>
void QuickSort( vector<T>& a ){
QuickSort( a, 0, a.size( )-1 );
}
template <typename T>
const T& Median3( vector<T>&a, int left, int right ){
int center = left + ((right - left) >> 1);
if (a[center] < a[left])
swap( a[left], a[center] );
if (a[right] < a[left])
swap( a[left], a[right] );
if (a[right] < a[center])
swap( a[center], a[right] );
swap( a[center], a[right - 1] );
return a[right - 1];
}
template <typename T>
void QuickSort( vector<T>& a, int left, int right ){
if (left + 10 <= right){
T pivot = median3( a, left, right );
int i = left;
int j = right - 1;
for ( ; ; ){
while (a[++i] < pivot)
;
while (a[--j] > pivot)
;
if ( i < j )
swap( a[i], a[j] );
else
break;
}
swap( a[i], a[right-1] );
QuickSort( a, left, i - 1 );
QuickSort( a, i + 1, right );
}
else
InsertSort( a, left, right );
}
11.插入排序
插入排序由N-1趟排序组成。对于p=1到N-1趟,插入排序保证从位置0到位置p上的元素为已排序状态。事实:位置0到位置p-1上的元素是已经排过序的。
在第p趟,我们将位置p上的元素向左移动至它在前p+1个元素中的正确位置上。
template <typename T>
void InsertSort( vector<T>& a ){
int j;
for (int p = 1; p < a.size( ); ++p){
T tmp = a[p];
for (j = p; j > 0 && tmp < a[j-1]; ++j)
a[j] = a[j-1];
a[j] = tmp;
}
}
12.冒泡、选择
void BubbleSort( void ){
int i = 0;
int j = 0;
for (i = 0; i < n - 1; ++i){
for ( j = 0; j < n - i - 1; ++j ){
/* */
}
}
}
void SelectSort( void ){
int maxIndex = 0;
int i = 0;
int j = 0;
for (i = 0; i < n - 1; ++i) {
maxIndex = i;
for ( j = i; j < n - 1; ++j )// j 从 i 开始;下来依次为 j < n - 1; arr[j + 1];//j 从 i + 1 开始,则依次为 j < n; arr[j]
{
if ( arr[j + 1] > arr[maxIndex] )
maxIndex = j + 1;
}
swap ( arr[i], arr[maxIndex] );
}
}