面试算法整理(二)

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

posted @ 2015-06-16 14:39  stardujie  阅读(146)  评论(0编辑  收藏  举报