剑指Offer读书笔记[1]

1、在定义一个赋值运算符时,通常需要考虑以下四点:

  • 是否将返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用(即*this)。只有一个返回引用,才可以允许连续赋值,否则如果函数的返回值是void,应用该赋值运算符将不能做连续赋值。
  • 是否将传入的参数类型声明为常量引用。如果传入的参数不是引用而是实例,那么从形参到实参会调用一次复制构造函数,把参数声明为引用可以避免这样的无谓消耗,能提高代码的效率。同时,我们在赋值运算函数内部不会改变传入的实例状态,因此应该在传入的引用参数前加上const关键字。
  • 是否释放实例已有的内存,如果我们忘记在分配新内存之前释放自身已有的空间,恒旭将出现内存泄漏。
  • 是否判断传入的参数和当前的实例是否是同一个实例。如果是同一个,则不进行赋值运算,直接返回,如果事先不判断就进行赋值,那么在释放实例自身内存的时候就会导致严重的问题,当*this和传入的参数是同一个实例时,一旦释放了自身的内存,传入的参数的内存将同时被释放,因此将再也找不到需要赋值的内容了。

当我们完整的考虑了上述四个方面以后,我们可以写出如下的代码:

CMyString& CMyString::operator = (const CMyString &str)
{
    if(this==&str)
      return;
    delete []m_pData;
    m_pData=NULL;
    m_pData=new char[strlen(str.m_pData)+1];
    strcpy(m_pData,str.m_pData);

    return *this;
}

2、要想在赋值运算符函数中实现异常安全性,我们有两种方法

  • 方法一:先用new分配新内容再用delete释放已有内容。这样只有当分配内容成功后再释放原来的内容,换句话说当分配内存失败时我们可以确定CMyString的实例不会被修改。
  • 方法二:先创建一个临时实例,再交换临时实例和原来的实例

下面给出第二种方法的实现代码:

CMyString& CMyString::operator = (const CMyString &str)
{
    if(this!=&str){

      CMyString strTemp(str);

      char* pTemp=strTemp.m_pData;
      strTemp.m_pData=m_pData;
      m_pData=pTemp;
  }

  return *this
}

3、对于C++和C#中的struct和class的认识

  • C++:在C++中如果没有标明成员函数或者成员变量的访问权限级别,则在struct中默认的是public,在class中的默认的private。
  • C#:在C#中如果没有标明成员函数或者成员变量的访问级别,则struct和class默认都是private,不同的是struct定义的是值类型,其实例在栈上分配内存;class定义的是引用类型,其实例在堆上分配内存。

4、在C#中实现单例模式

  • 原理:在C#语法中C#是在调用静态函数时初始化静态变量,.NET运行时可以保证只调用一次静态构造函数,这样我们就可以保证仅初始化一次Instance;

    下面给出代码示例:

public sealed class Singleton
{
    private Singleton()
  {

  }

  private static Singleton instance=new Singleton();
  public static Singleton Instance
  {
    get{ return instance;}
  }
}

5、C++数组重要概念

  • 数组是最简单的一种数据结构,它占据一块连续的内存并按照顺序存储数据。
  • 在C/C++中,数组和指针是相互关联又有区别的两个概念。当我们声明一个数组时,其数组的名字同时是一个指针,该指针指向数组的第一个元素,因此我们可以使用一个指针来访问数组。可是值得注意的是,C/C++并没有记录数组的大小,因此使用指针访问数组中的元素时要注意不能超出数组的边界。
  • 使用sizeof计算指针的大小时,在32位操作系统中,对于任意指针结果都是4。
  • 二维数组在内存中占据连续的空间。在内存中从上到下存储各行元素,在同一行中按照从左到右的顺序存储。因此我们可以根据行号和列号计算出相对于数组首地址的偏移量,从而找到对应的元素。

6、C#中的String类型

  • 在C#中封装字符串的类型Sysytem.String有一个非常特殊的性质,即String中的内容是不能改变的。当尝试改变String中的内容,就会产生一个新的实例。
  • 如果要连续多次修改字符串内容,可以考虑使用StringBuilder。
  • 当我们需要在函数或者方法中返回一个String实例时,我们需要在传入的参数前加上ref或者out标记

7、链表

  • 链表是一种动态数据结构,因为在创建链表的时候,不需要知道链表的长度。当插入一个结点时,我们只需要为新结点分配内存,然后调整指针的指向来确保新结点被链接到链表当中。内存分配不是在创建链表时一次性完成,而是每添加一个结点分配一次内存。由于没有闲置的内存,因此链表的空间效率比数组要高。
  • 因为链表中的内存不是一次性分配的,所以我们不能确定链表的内存和数组一样是连续的,因此如果想在链表中找到第i个结点,我们只能从头结点开始,沿着指向下一个结点的指针遍历链表,其效率是O(n)。而在数组中,我们可以根据下标i直接找到第i个元素,其效率是O(1)。
  • 当我们需要从尾到头输出链表时,第一个遍历到的结点最后一个输出,而最后一个遍历到的结点第一个输出,这是典型的后进先出,因此我们可以考虑使用栈来实现这种顺序。下面是具体的代码实现:
void PrintListReversingly_Iteratively(ListNode* pHead)
{
    std::stack<ListNode*> nodes;

    ListNode* pNode=pHead;
    while(pNode!=NULL)
    {
      nodes.push(pNode);
      pNode=pNode->m_pNext;
    }

    while(!nodes.empty())
    {
      pNode=nodes.top();
      printf("%d\t",pNode->m_nValue);
      nodes.pop();
    }
}

8、树

  • 除了根节点之外每个结点只有一个父结点,根节点没有父结点。
  • 除了叶节点以外所有结点都有一个或者多个子结点,叶结点没有子结点。父结点和子结点间用指针链接。
  • 二叉树是树的一类特殊结构,在二叉树的每个结点最多只能有两个子结点。二叉树有三种主要的遍历方式,即前序遍历(根、左、右)、中序遍历(左、根、右)、后序遍历(左、右、根)。
  • 二叉搜索树是二叉树的一个特例,其特点是左子节点总是小于或等于根节点,右子结点总是大于或等于根节点。

9、栈和队列

  • 栈的特点是后进先出,即最后一个被压入(Push)栈的元素会第一个被弹出(Pop)。
  • 队列的特点是先进先出,即第一个进入队列(入队)的元素将会第一个出来(出队)。

10、递归与循环

  • 递归实现的效率无法和循环相比,因此函数调用会造成时间和空间的损失、会造成重复计算、可能会造成栈溢出。

    在经典的斐波那契数列问题中,我们可以采用下面的方法来代替传统的递归方法:

int Fiboncci(int n)
{
  int[] result=new int[]{0,1};
  if(n<2)
     return result[n];

  int m=1;
  int n=0;
  int k=0;
  for(int i=2;i<=n;i++)
  {
     k=m+n;
     n=m;
     m=k;
  }

  return k;
}

11、位运算

  • 左移m<
时间: 2024-11-05 16:03:15

剑指Offer读书笔记[1]的相关文章

剑指offer 学习笔记

主题:二维数组中的查找 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 思路分析:首先分析题目描述,二维数组行递增,列递增,这种特性不同于混乱无序的数组查找,因此排除在数组中逐个查找目标元素的做法. 1   2   8     9 2   4   9    12 4   7   10  13 6   8   11  15 考虑从左上角开始查找,这个元素是整个数组中最小的元

剑指Offer——银行考试

剑指Offer--银行考试 网申简历 一. 银行网申简历主要看哪些方面? 1.职业形象(30%),基本体现为证件照: 2.学校+成绩+校内表现(40%),体现为证书,成绩排名以及任职经历等: 3.校外实践(20%),主要体现在工作实习.实践活动和培训经历三点: 4.其他(10%),根据简历的完整性.准确性,进行综合评定. 二.网申简历应注意哪些方面? 1.考虑银行人的思维习惯(考虑岗位匹配度) 例:申请职位为柜员时,就应该在简历中体现出热情.乐于帮助他人.沉稳细心.认真大方,具有服务意识且对数字

【剑指offer】Q38:数字在数组中出现的次数

与折半查找是同一个模式,不同的是,在这里不在查找某个确定的值,而是查找确定值所在的上下边界. def getBounder(data, k, start, end, low_bound = False): if end < start : return -1 while start <= end: mid = ( start + end ) >> 1 if data[ mid ] > k: end = mid - 1 elif data[ mid ] < k: star

【剑指offer】树的子结构

转载请注明出处:http://blog.csdn.net/ns_code/article/details/25907685 剑指offer第18题,九度OJ上测试通过! 题目描述: 输入两颗二叉树A,B,判断B是不是A的子结构. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行一个整数n,m(1<=n<=1000,1<=m<=1000):n代表将要输入的二叉树A的节点个数(节点从1开始计数),m代表将要输入的二叉树B的节点个数(节点从1开始计数).

【剑指offer】二叉树的镜像

转载请注明出处:http://blog.csdn.net/ns_code/article/details/25915971 题目描述: 输入一个二叉树,输出其镜像. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000,n代表将要输入的二叉树节点的个数(节点从1开始编号).接下来一行有n个数字,代表第i个二叉树节点的元素的值.接下来有n行,每行有一个字母Ci.Ci='d'表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号.C

【剑指offer】数组中仅仅出现一次的数字(1)

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27649027 题目描写叙述: 一个整型数组里除了两个数字之外,其它的数字都出现了两次.请敲代码找出这两个仅仅出现一次的数字. 输入: 每一个測试案例包括两行: 第一行包括一个整数n,表示数组大小.2<=n <= 10^6. 第二行包括n个整数,表示数组元素,元素均为int. 输出: 相应每一个測试案例.输出数组中仅仅出现一次的两个数.输出的数字从小到大的顺序. 例子输入: 8 2 4

牛客网上的剑指offer题目

题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 题目:请实现一个函数,将一个字符串中的空格替换成"%20" 两种方法实现:输入一个链表,从尾到头打印链表每个节点的值 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 剑指offer 斐波那契数列 一只青蛙一次可以跳上1级台阶,也可以跳上2级--它也可以跳上n级.求该青蛙跳上一个

剑指Offer——如何做好自我介绍

剑指Offer--如何做好自我介绍 前言 自我特点+经历梳理 ??各位老师好,我叫某某某,研究生三年级,就读于某某大学信息科学与工程学院软件工程专业.主要使用的开发语言是Java,熟悉基本数据结构和基本算法实现:熟悉MySQL数据库:掌握Linux基本操作命令:所参与的主要项目有"立马送药","鲜花礼品网","基于Android实现的购彩系统"和"我看看"购物分享Android APP.其中,"立马送药"的

剑指Offer——Trie树(字典树)

剑指Offer--Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高. Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.可见,优