关闭

高质量的代码

标签: 面试题工作性能
83人阅读 评论(0) 收藏 举报
分类:

多看了看剑指offer这本书,发现里面面试题的实现其实只是例子,其目的是发散我们的思维,让我们从多个不同的角度去思考问题,要考虑全面,还要考虑性能,这肯定都是工作中很重要的必须被重视的东西,例子只是其次,重要的是理解例子传递出来的要点思想,这是我的目前为止一点点的个人感悟
小知识:
(1)double类型的数据不能够通过==来比较,因为精度会受到影响
(2)代码规范的三个重要性,书写,布局,函数变量名称的命名
(3)代码的完整性,功能测试,边界测试,负面测试(错误输入)
要考虑突破自己的常规思维,要多想测试用例,这个是一般学生都欠缺的思维方式,因为我们重点一般都是如何实现功能,很少有人会去写测试用例(起码我身边的人和自己开始都是这样的啦,但是正在努力转变思维中)
三种处理方式:
(1)返回值:
优点:和系统API一致
缺点:不能方便地使用计算结果
(2)全局变量:
优点:能方便的使用计算结果
缺点:用户可能会忘记检查全局变量
(3)异常:
优点:可以为不同的出错原因定义不同异常类型,逻辑清晰明了
缺点:有些语言不支持异常,抛出异常时对性能有负面影响

面试题:数值的整数次方(不需要考虑大数情况)
double Power(double base,int exponent);
思路:
(1)正整数的次方谁都会写,但是一般人就只考虑了正整数的情况
(2)还有负数的情况
(3)0的0次方的情况
(4)由于他已经给了次方是整数形式,所以我们不需要考虑小数形式
注意double类型的比较不能用单一的==
可以自己规定一个范围
abs(num1-num2)<0.000000001
还可以对效率进行提升,比如2的16次方是2的八次方乘2的八次方依次下去,核心还是要考虑多种情况,在异常全部考虑的情况下就要去思考效率了

面试题:打印1到最大的n位数(重点是考虑大数)
自己完成的代码

class number
{
    int* arrNum;
    int len;
public:
    number(int n)
    {
        len = n;
        arrNum = (int*)malloc(sizeof(int)*n);
        for (int i = 0; i < len; ++i)
        {
            arrNum[i] = 0;
        }//初始化
    }
    ~number()
    {
        free(arrNum);
    }

    bool judgeMax()
    {
        for (int i = 0; i < len; ++i)
        {
            if (arrNum[i] == 9)
            {
                continue;
            }
            else
            {
                return false;
            }
        }
        return true;
    }

    void show()
    {
        if (len <= 0)
        {
            cout << "输入错误,请重新输入\n";
        }
        else
        {
            while (judgeMax()==false)
            {
                arrNum[0] = arrNum[0] + 1;
                if (arrNum[0] == 10)
                {
                    arrNum[0] = 0;
                    for (int i = 1; i < len; ++i)
                    {
                        arrNum[i] = arrNum[i] + 1;
                        if (arrNum[i] == 10)
                        {
                            arrNum[i] = 0;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                for (int i = len-1; i >= 0; --i)
                {
                    if (arrNum[i] != 0||i==0)
                    {
                        cout << arrNum[i];
                    }
                }
                cout << endl;
            }

        }
    }
};

int main()
{
    int num;
    while (1)
    {
        cout << "请输入您需要的信息" << endl;
        cin >> num;
        number tmp(num);
        tmp.show();
    }
}

调整数组顺序使奇数位于偶数前
博主自己也写了一个复杂度O(n)的函数实现,但是看了看人家的,还是人家的思路清晰一些,所以我就直接把书上的代码贴上来了
算法复杂度O(n)

void RecorderOddEven(int *pData,unsigned int length)
{
if(pData==NULL||length==0)
return;

int *pBegin = pData;
int *pEnd = pData+length-1;

while(pBegin<pEnd)
{
   //向后移动pBegin,直到它指向偶数或者等于pEnd
   while(pBegin<pEnd&&(*pBegin&0x1)!=0)
   pBegin++;

   //向前移动pEnd,直到它指向奇数
   while(pBegin<pEnd&&(*pEnd&0x1)==0)
   pEnd--;

   if(pBegin<pEnd)
   {
       int temp = *pBegin;
       *pBegin = *pEnd;
       *pEnd = temp;
   } 
}

拓展思路:
如果让你求所有负数都在非负数前面,该怎么做?
如果让你求所有能被3整除的数在前面,而不能被3整除的数在后面怎么办?
这时候我的第一个想法是C++的模板
联系一下C语言,发现作如上更改的关键不过就是大循环内两个小循环的判断条件的更改,
那么此时我们可以考虑传入函数指针的方法来实现C语言的模板化

void Reorder(int* pData,unsigned int length,bool (*func)(int))
{
  if(pData==NULL||length==0)
  return;

  int *pBegin = pData;
  int *pEnd = pData + length - 1;

  while(pBegin<pEnd)
  {
    while(pBegin<pEnd&&!func(*pBegin))
   pBegin++;

   //向前移动pEnd,直到它指向奇数
   while(pBegin<pEnd&&func(*pEnd))
   pEnd--;

   if(pBegin<pEnd)
   {
       int temp = *pBegin;
       *pBegin = *pEnd;
       *pEnd = temp;
   } 
  }
}
bool isEven(int n)
{
   return (n&1)==0;//判断条件
}
//调用的时候直接把函数名称传递进去就好了,主要优点是提高了代码的可重用性

。。。之前还写了两道题和总结, 结果。。忘记保存了,无凑,心里苦,但是内容是链表的,所以都很简单就不再写了
树的子结构
输入两颗二叉树A和B,判断B是不是A的子结构
看到题目的个人第一反应
(1)B要是空树则不管A是不是空树B一定是A的子结构(理论依据空集是任何集合的子集)
(2)B要是高度比A高那么一定不是A的子结构
(3)B要是结点个数比A多那么一定不是A的子结构
代码如下(已经输入了各种情况参数确认都可以得出合理的结果)

int getDepth(treeNode* s)//获取二叉树深度
{
    if (s == NULL)
    {
        return 0;
    }
    else
    {
        int tmp1 = getDepth(s->left);
        int tmp2 = getDepth(s->right);
        return (tmp1> tmp2 ? tmp1 : tmp2) + 1;
    }
}

int getSize(treeNode* s)//获取二叉树结点数目
{
    if (s == NULL)
    {
        return 0;
    }
    else
    {
        return getSize(s->left) + getSize(s->right) + 1;
    }
}

bool compare(treeNode* A, treeNode* B)//比较A,B两棵树,B是否是A的子树,注意传入的参数A->data==B->data
{
    if (A == NULL&&B == NULL)
    {
        return true;
    }
    if (A == NULL&&B != NULL)
    {
        return false;
    }
    if (A != NULL&&B == NULL)//B是A的子就好了
    {
        return true;
    }
    if (A->data != B->data)
    {
        return false;
    }
    else
    {
        return compare(A->left, B->left) && compare(A->right, B->right);
    }
}


treeNode* findSame(treeNode* A, treeNode* B)//找A结点和B的相同的那个结点
{
    if (A == NULL)
    {
        return NULL;
    }
    if (A->data == B->data)
    {
        return A;
    }
    treeNode* tmp1 = findSame(A->left, B);
    treeNode* tmp2 = findSame(A->right, B);
    if (tmp1 == NULL&&tmp2 == NULL)
    {
        return NULL;
    }
    if (tmp1 != NULL)
    {
        return tmp1;
    }
    else
    {
        return tmp2;
    }
}

//已知二叉树没有重复的结点,最终调用的函数
bool isSon(treeNode* A, treeNode* B)
{
    if (B == NULL)
    {
        return true;
    }
    if (getDepth(B) > getDepth(A))
    {
        return false;
    }
    if (getSize(B) > getSize(A))
    {
        return false;
    }
    treeNode* tmp = findSame(A, B);
    if (tmp == NULL)
    {
        return false;
    }
    return compare(tmp, B);
}

看了下参考答案好像我自作聪明了。。。求深度要遍历,求结点个数也要遍历,从思想上好像我的是简化了,但是对计算机而言并没有简化,所以。。可以去掉求高求深度直接开始遍历看是不是子树相对于计算机而言效率还要更高一些

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:45368次
    • 积分:2294
    • 等级:
    • 排名:第17105名
    • 原创:190篇
    • 转载:3篇
    • 译文:0篇
    • 评论:8条
    最新评论