zoukankan      html  css  js  c++  java
  • 高质量的代码

    double类型的比较不能用==

    计算机表示的小数(包括float & double)都有误差,如果两个小数的差的绝对值很小,小雨0.0000001(中间为6个0)就可以认为他们相等

    完整的代码:功能测试,边界测试,负面测试

    考虑题目是否会出现大数问题,超出int的可以用long long
    负面测试是指输入的数据是非法的错误的
     
    3种错误处理方法:


    1.不同的返回值表示不同的错误

    2.
    3.抛出异常时,程序的执行会打乱正常的顺序,对程序的性能有很大的影响。
     


     

    面试题11:数值的整数次方

     注意各种输入,base为0.0,exponent为负数时是错误输入

     exponent为负数,取绝对值,求幂后倒数,

     注意浮点数的比较相等用差值和0.0000001

     求幂用递归,a的n次方分奇偶考虑,偶数的时候就用a的n/2的平方

     除以2的时候用位移,体现细节..

    面试题12:打印1到最大n位数

    n位数可能会超出long long的范围,long long 为8字节64位

    -->用字符串模拟数字的加法 

    复制代码
      1  
      2  /*n位数可能会超出long long的范围,long long 为8字节64位
      3      -->用字符串模拟数字的加法*/
      4  #include <memory>
      5  #include <string.h>
      6  //C++ 中要使用strlen一般包含<CString>
      7  
      8  //一直进位直到第一次结束才是一个+1过程的结束
      9  bool Increment(char* number)
     10  {
     11      int length = strlen(number);
     12      int takeOver = 0;
     13      bool isOverStack = false;
     14      
     15      for(int i = length - 1; i >= 0; ++i)
     16      {
     17          int sum = number[i] - '0' + takeOver;
     18          if(i == length - 1)
     19              ++sum;
     20  
     21          if(sum >= 10)
     22          {
     23              if(i == 0)
     24                  isOverStack = true;
     25              else
     26              {
     27                  sum -= 10;
     28                  number[i] = sum + '0';
     29                  takeOver = 1;
     30              }
     31          }
     32          else
     33          {
     34              number[i] = sum + '0';
     35              break;
     36          }
     37  
     38      }
     39      return isOverStack;
     40  }
     41  
     42  //不要打印出最前面的0
     43  void PrintNumber(char* number)
     44  {
     45      int length = strlen(number);
     46      bool posFlag = false;
     47  
     48      for(int i = 0; i < length; ++i)
     49      {
     50          if(!posFlag && number[i] != '0')
     51              posFlag = true;
     52          if(posFlag)
     53              printf("%c", number[i]);
     54      }
     55      return;
     56  }
     57  
     58  void PrintToMaxOfNDigits(int n)
     59  {
     60      if(n <= 0)
     61          return;
     62      char *number = new char[n + 1];
     63      memset(number, '0', n);
     64      number[n] = '';
     65  
     66      while(!Increment(number))
     67          PrintNumber(number);
     68      delete []number;
     69  }
     70  
     71  //把问题转换为数字排列的方法,运用递归是程序更加简单
     72  //全排列方法
     73  
     74  void PrintToMaxOfNDigits_1(int n)
     75  {
     76      char* number = new char[n + 1];
     77      memset(number, '0', n);
     78      number[n] = '';
     79      for(int i = 0; i < 10; ++i)
     80      {
     81          number[0] = '0' + i;
     82          PrintRecursively(number, n, 0)
     83      } 
     84      delete []number;
     85  }
     86  
     87  void PrintRecursively(char* number, int length, int index)
     88  {
     89      if(index == length - 1)
     90      {
     91          PrintNumber(number);
     92          return;
     93      }
     94  
     95      for(int i = 0; i < 10; ++i)
     96      {
     97          number[index + 1] = '0' + i;
     98          PrintRecursively(number, length, index + 1);
     99      }
    100  }
    复制代码

     面试题13:在O(1)时间内删除链表节点

    把下一个节点的内容复制到需要删除的节点上覆盖原有的内容,再把下一个节点删除即可。

    若删除的节点位于列表尾部则顺序遍历得到该节点的前序节点,并完成删除操作。

    如果链表中只有一个节点,则在删除后还需要把链表的头结点设置为NULL。

    //题目已经假设删除的节点一定在链表中

    //节点delete之后,要将本身设为NULL,position本身就是一个节点指针,是有指向的

    复制代码
     1 #include <iostream>
     2 using namespace std;
     3 
     4 typedef struct ListNode* head;
     5 typedef struct ListNode* position;
     6 struct ListNode
     7 {
     8     int m_nValue;
     9     ListNode* m_pNext;
    10 };
    11 
    12 void DeleteNode(head pListHead, position pToBeDeleted)
    13 {
    14     if(!pListHead || !pToBeDeleted)
    15         return;
    16     position pTemp;
    17     if(pToBeDeleted->m_pNext == NULL)
    18     {
    19         pTemp = pListHead;
    20         while(pTemp->m_pNext != pToBeDeleted)
    21             pTemp = pTemp->m_pNext;
    22         pTemp->m_pNext = pToBeDeleted->m_pNext;
    23         delete pToBeDeleted;
    24         //注意下面一行
    25         pToBeDeleted = NULL;
    26         return;
    27     }
    28     pTemp = pToBeDeleted->m_pNext;
    29     pToBeDeleted->m_nValue = pTemp->m_nValue;
    30     pToBeDeleted->m_pNext = pTemp->m_pNext;
    31     delete pTemp;
    32     //注意下面一句
    33     pTemp = NULL;
    34     return;
    35 }
    复制代码

    面试题14:调整数组顺序使奇数位位于偶数之前

    题目:输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。

    用和快排比较相似的算法,维护两个指针

    通常情况下位运算符比%要快一些,所以判断奇偶可以用data & 0X1 比较好

    复制代码
     1 #include<iostream>
     2 using namespace std;
     3 void ReorderOddEven(int *number, unsigned int length)
     4 {
     5     //函数初始时基本的判断参数输入有没有错误的不要忘了!!!
     6     if(number == NULL || length == 0)
     7         return;
     8 
     9     int *p1 = number, *p2 = number + (length -1);
    10     while(p1 < p2)
    11     {
    12         while(p1 < p2 && (*p1 & 0x1) == 1)
    13             ++p1;
    14         while(p1 < p2 && (*p2 & 0x1) == 0)
    15             --p2;
    16         if(p1 < p2)
    17         {
    18             int temp = *p1;
    19             *p1 = *p2;
    20             *p2 = temp;
    21         }
    22         
    23     }
    24     return;
    25 }
    复制代码

    可以利用函数指针把这个算法扩展

    复制代码
     1 void Reorder(int* number, unsigned int length, bool (*func)(int))
     2 {
     3     //函数初始时基本的判断参数输入有没有错误的不要忘了!!!
     4     if(number == NULL || length == 0)
     5         return;
     6 
     7     int *p1 = number, *p2 = number + (length -1);
     8     while(p1 < p2)
     9     {
    10         while(p1 < p2 && !func(*p1))
    11             ++p1;
    12         while(p1 < p2 && func(*p2))
    13             --p2;
    14         if(p1 < p2)
    15         {
    16             int temp = *p1;
    17             *p1 = *p2;
    18             *p2 = temp;
    19         }
    20 
    21     }
    22     return;
    23 }
    24 
    25 bool isEven(int n)
    26 {
    27     return (n & 0x1) == 0;
    28 }
    29 void ReorderOddEven2(int* number, unsigned int length)
    30 {
    31     Reorder(number, length, isEven);
    32 }
    复制代码

    代码的鲁棒性:

    容错性是代码鲁棒性的一个重要体现

    1.输入错误的用户名

    2.试图打开不存在的文件

    3.网络不能连接

    4......

    -->预防性编程

    面试题15:链表中倒数第k个结点

    题目:输入一个单向链表,输出该链表中倒数第k个结点。链表的倒数第0个结点为链表的尾指针。链表结点定义如下:

    记尾节点是倒数第一个节点,

    用unsigned int 来表示length比较合理,此时0 - 1得到一个巨大的数

    复制代码
     1 #include <iostream>
     2 using namespace std;
     3 typedef struct ListNode* phead;
     4 typedef struct ListNode* position;
     5 struct ListNode
     6 {
     7     int m_nValue;
     8     ListNode* m_pNext;
     9 };
    10 
    11 position FindKthNode(phead listHead, unsigned int k)
    12 {
    13     if(listHead == NULL || k == 0)
    14         return NULL;
    15     position temp1 = listHead, temp2 = listHead;
    16 
    17     for(unsigned int i = 0; i < k - 1; ++i)
    18     {
    19         if(temp1->m_pNext != NULL)
    20             temp1 = temp1->m_pNext;
    21         else
    22             return NULL;
    23     }
    24     while(temp1->m_pNext != NULL)
    25     {
    26         temp1 = temp1->m_pNext;
    27         temp2 = temp2->m_pNext;
    28     }
    29     return temp2;
    30 }
    复制代码

    要注意K=0,listHead指向空,list长度小于K

    1.求链表的中间节点:

      若链表总数为奇数,返回中间节点,否则返回中间节点2个中的任意一个

      定义两个指针都从链表头结点出发,一个一次走一步,一个一次走两步,走的快的到末尾时,走的啊,慢的刚好在链表的中间

    2.判断一个链表是否构成环形;

      同上,定义两个指针都从链表头结点出发,一个一次走一步,一个一次走两步,走的快如果能追上走的慢的那么就是环形链表,如果到链表末尾还没有追上走的慢的则不是环形链表

     

    当我们使用一个指针遍历链表不能解决问题的时候,可以尝试用两个指针来遍历,两个指针遍历的速度或者先后不同。

     

    面试题16:反转链表

    输入的链表指针为NULL或者整个链表只有一个节点

    反转后头结点是不是链表的原先的尾节点

    复制代码
     1 #include<iostream>
     2 using namespace std;
     3 typedef struct ListNode* pHead;
     4 typedef struct ListNode* position;
     5 
     6 struct ListNode
     7 {
     8     int m_nValue;
     9     ListNode* m_pNext;
    10 };
    11 
    12 pHead ReverseList(pHead listHead)
    13 {
    14     pHead pReversedHead = NULL;
    15     position pNode = listHead;
    16     position pPrev = NULL;
    17 
    18     //这种形式中头结点不是哑元,反转后头结点为的下一个为NULL
    19     //所以初始的pPrev设为NULL
    20     
    21     while(pNode != NULL)
    22     {
    23         position pNext = pNode->m_pNext;
    24         if(pNext == NULL)
    25             pReversedHead = pNode;
    26 
    27         pNode->m_pNext = pPrev;
    28         pPrev = pNode;
    29         pNode = pNext;
    30     }
    31     return pReversedHead;
    32 }
    复制代码

    递归实现注意头结点的6,7,8行是最后实现的

    复制代码
    1 Node * resverselinkRecursion(Node *head) 
    2 {
    3  if(head==NULL || head->next==NULL)
    4   return head;
    5  Node *n = resverselinkRecursion(head->next);
    6  head->next->next = head;
    7  head->next=NULL;
    8  return n;
    9 }
    复制代码

     面试题18:树的子结构

    判断二叉树B是不是A的子结构

    复制代码
     1 #include<iostream>
     2 using namespace std;
     3 
     4 typedef struct BinaryTreeNode* position;
     5 typedef struct BinaryTreeNode* root;
     6 struct BinaryTreeNode
     7 {
     8     int            m_nValue;
     9     position    m_pLeft;
    10     position    m_pRight;
    11 };
    12 
    13 bool HasSubTree(root pRoot1, root pRoot2)
    14 {
    15     bool result = false;
    16     if(pRoot1 != NULL && pRoot2 != NULL)
    17     {
    18         if(pRoot1->m_nValue == pRoot2->m_nValue)
    19             result = DoesTree1HaveTree2(pRoot1, pRoot2);
    20         if(!result)
    21             result = HasSubTree(pRoot1->m_pLeft, pRoot2);
    22         if(!result)
    23             result = HasSubTree(pRoot1->m_pRight, pRoot2);
    24     }
    25     return result;
    26 }
    27 
    28 bool DoesTree1HaveTree2(root pRoot1, root pRoot2)
    29 {
    30     if(pRoot2 == NULL)
    31         return true;
    32     if(pRoot1 == NULL)
    33         return false;
    34     if(pRoot1->m_nValue != pRoot2->m_nValue)
    35         return false;
    36     return DoesTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) &&
    37         DoesTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight);
    38 }
    复制代码

    树的操作都伴随着大量的指针,尤其要考虑清楚是否为NULL的情况。

  • 相关阅读:
    通用权限的思路。带有数据库关系图
    三层架构之我见 —— 不同于您见过的三层架构。
    n级分类的数据结构
    JS经典源码:通用JavaScript脚本函数库
    SQL 复习笔记
    ASP.net实现无扩展名的URL重写。简单、方便、无需ISAPI。
    DataSet导出到Excel比较完整的解决方案(二)服务器端生成文件(downmoon)
    DataSet导出到Excel比较完整的解决方案(一)客户端生成文件(downmoon)
    Squid详细配置实用文档
    Awstats分析nginx日志
  • 原文地址:https://www.cnblogs.com/zsq1993/p/5985181.html
Copyright © 2011-2022 走看看