面试算法整理(二)
strcpy函数的实现
已知strcpy函数的原型是:
char* strcpy(char* dst, char* src);
1、实现strcpy函数
char* strcpy(char* dst, const char* src)
{
assert(dst != NULL && src != NULL);
char* ret = dst;
while((*dst++ = *src++) != '\0');
return ret;
}
2、解释为什么要返回char*
返回dst的原始值使得函数能够支持链式表达式。
链式表达式的形式如:
int l = strlen(strcpy(strA, strB));
又如:
char* strA = strcpy(new char[10], strB);
返回strSrc的原始值是错误的。
第一,源字符串肯定是已知的,返回它没有意义。
第二,不能支持形如第二例的表达式
第三,把const char*作为char返回,类型不符,编译报错。
3、加入考虑dst和src内存重叠的情况,strcpy怎么实现
char s[10] = "hello";
strcpy(s, s+1); //应该返回ello
//strcpy(s+1, s); //应该返回hhello,但是实际会报错,因为dst与src重叠了,把'\0'覆盖了
所谓重叠,就是src未处理的部分已经被dst给覆盖了,只有一种情况:
src <= dst <= src+strlen(src)
C函数memcpy自带内存重叠检测功能。
char* strcpy(char* dst, const char* src)
{
assert(dst != NULL && src != NULL);
char* ret = dst;
my_memcpy(dst, src, strlen(src)+1);
return ret;
}
my_memcpy的实现如下:
char* my_memcpy(char* dst, char* src, int cnt)
{
assert(dst != NULL && src != NULL);
char* ret = dst;
if(dst >= src && dst <= src+cnt-1)//内存重叠,从高地址开始复制
{
dst = dst+cnt-1;
src = src+cnt-1;
while(cnt--)
*dst-- = *src--;
}
else //正常情况,从低地址开始复制
{
while(cnt--)
*dst++ = *src++;
}
return ret;
}
已知类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(str == NULL) //strlen在参数为NULL的时候会抛异常才会有这步判断
{
m_data= new char[1];
m_data[0] = "";
}
else
{
m_data = new char[strlen(str)+1];
strcpy(m_data, str);
}
}
String::String(const String &other)
{
m_data = new char[strlen(other.m_data)+1];
strcpy(m_data, other.m_data);
}
String &String::operator = (const String &other)
{
if(this == &other)
return *this;
delete[] m_data;
m_data = new char[strlen(other.m_data)+1];
strcpy(m_data, other.m_data);
return* this;
}
String::~String(void)
{
delete[] m_data;
}
文件中有一组整数,要求排序后输出到另一个文件中
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <fstream>
using namespace std;
void Order(vector<int> data);
static void swap(int& a, int& b);
int main(int argc, char* argv[])
{
vector<int> data;
ifstream in("test.txt");
if(!in)
{
cout << "file error!";
exit(1);
}
int tmp, i;
while(!in.eof())
{
in >> tmp;
data.push_back(tmp);
}
in.close();
Order(data);
ofstream out("result.txt");
if(!out)
{
cout << "file error!";
exit(1);
}
for(i = 0; i < data.size(); i++)
{
cout << data[i] << " ";
}
cout << endl;
out.close();
return 0;
}
static void swap(int& a, int& b)
{
int temp;
temp = a;
a = b;
b = temp;
}
void Order(vector<int> data)
{
int count = data.size();
int i, j;
int tag = false;
for(i = 0; i < count; i++)
{
for(j = 0; j < counnt-i-1; j++)
{
if(data[j] > data[j+1])
{
tag = true;
swap(data[j], data[j+1]);
}
}
if(!tag)
break;
}
}
将一个链表反转
#include <iostream>
#include <cstdlib>
using namespace std;
class node
{
public:
node* next;
int data;
};
node* test = NULL;
node* nodereverse(node* head)
{
//如果一个函数的输入参数有指针,一定要记住判断指针是否为空
//1、在使用一个指针之前一定要判断它是否为空
//2、使用完后要释放由指针指向的存储单元
//3、释放完存储单元后要将指针赋值为NULL
if(head->next == NULL || head == NULL)
return head;
node* temp1 = head;
node* temp2 = NULL;
node* temp3 = head->next;
temp1->next = NULL;
//要注意这里面的顺序,先将temp3保存在temp2中,然后再将temp3移动到下一个元素,然后才能改动temp2
while(temp3->next != NULL)
{
temp2 = temp3;
temp3 = temp3->next;
temp2->next = temp1;//不能在temp3 = temp3->next;之前执行
temp1 = temp2;
}
temp3->next = temp2;
return temp3;
}
void initnode()
{
node* tmp = NULL;
for(int i = 0; i < 4; i++)
{
tmp = new node;
tmp->data = i;
tmp->next = test;
test = tmp;
}
}
void display(node* nn)
{
if(nn == NULL)
{
cout << "no data to display!\n";
return;
}
node* dis = nn;
while(dis != NULL)
{
cout << dis->data << endl;
dis = dis->next;
}
}
//释放动态申请空间
void distroy(node* nn)
{
if(nn == NULL)
{
return;
}
while(nn != NULL)
{
node* tmp = nn;
nn = nn->next;
delete tmp;
}
}
int main(int argc, char* argv[])
{
initnode();
display(test);
cout << "**********" << endl;
node *tmp = nodereverse(test);
if(test == NULL)
exit(0);
display(tmp);
//tmp和test指向的存储空间使用完毕,应该释放掉他们申请的空间!
//并且,要将他们赋值为NULL,否则他们将成为野指针!
distroy(tmp); //释放动态申请的内存
tmp = NULL; //将他们重新赋值为NULL,不然会成为野指针
test = NULL;
cout << "tmp= " << tmp << endl;
//如果上面没有tmp= NULL;test = NULL;display将会出错,
//因为在display开始的时候判断传入的参数是否为NULL,如果不把野指针赋值为NULL,那么判断就没有效果,
//会继续指向display中的while语句,而此时指针所指向的存储空间已经被释放掉了,这样就会出现异常。
display(test);
system("pause");
return 0;
}
具体更详细的参考:http://www.cnblogs.com/BeyondAnyTime/archive/2012/07/06/2580026.html