zoukankan      html  css  js  c++  java
  • 面试算法整理(二)

    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++) != '');
    	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重叠了,把''覆盖了
    

    所谓重叠,就是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!
    ";
    		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

  • 相关阅读:
    前端二维码生成方式
    svn 本地仓库使用
    layer.open实现图片预览
    基于FreethEarh框架开发的3D综合态势系统
    Cesium原理篇:6 Render模块(5: VAO&RenderState&Command)【转】
    Cesium中DrawCommand使用【转】
    Cesium案例解析(三)——Camera相机[转]
    Cesium.knockout【转】
    Java堆和栈的区别
    Kafka Eagle安装详情及问题解答
  • 原文地址:https://www.cnblogs.com/stardujie89/p/4580752.html
Copyright © 2011-2022 走看看