C++笔记     第十四天         2007年4月10日
                       
1、对文件的分类
  (1)文本文件:每个字节都是有效的可显示的ASCII码 ,getline() , >>
  (2)二进制文件:字节是连续的,不能用vi , more查看文件内容,read按字节数读取 , write                       
 
  100 是整数的100,占4个字节
   “100”是字符数组,占3个字节
  
2、异常
   (1)人为错误:由于程序员编码不当
        客观错误:不能避免的错误
       
   (2)通过返回值判断程序的错误情况,对调用者的要求高,要写if()else()判断,而且对于返回值的含义要非常的清楚
        所以C++中提供了异常处理机制
       
3  异常的工作原理:
    1) 程序员写的代码在出现意外的地方自动产生一个异常,然后抛出一个异常对象。
    2) 对象被传递到负责异常处理的地方。
            throw 1;  //抛出异常,让调用者处理
    3) 由负责异常处理的代码进行统一的异常处理。 try{}catch(){}
    4) 异常对象包含有意外发生的详细信息。

4  异常代码的格式:
    抛出: throw 异常名字;
   
    处理: ppt368
   
    try {

} catch( 异常1  int) {
        处理代码;
    } catch( 异常2  const char* ) {
         处理代码;
    }
    程序正常的时候,catch块什么也不做,当出现异常的时候,程序从产生异常的地方跳到catch块中
    异常处理完毕之后,不会回到发生异常的地方。
    用try{}catch(){}处理异常是一种强制手段,出现异常,进程结束
    catch()中的异常类型如果与抛出的异常类型不一致,则捕获不到

5  每个catch只能处理一种类型的异常,catch块会依次执行。

6  catch(...){
        处理代码;
    }
    可以捕获任意类型的异常,但是它不能判断是什么类型的异常,一般把它放在最后一个catch块。
    但这种捕获没有针对性

7 异常的传播特性:
   层级传播:异常会逐层抛出
   产生异常之后,程序立即跳转到最近的一层捕获异常的语句,如果当前没有捕获语句,或者没有匹配的catch块,那么程序会跳出当前的函数回到调用的地方。
   如果向上跳到了main函数,还是没有处理异常,程序就会终止进程。 
  
8、封装异常(1)使用字符串描述异常
           (2)制定异常号 error No.
           (3)disp();            
   当捕获的异常存在继承关系的时候,要先捕获子类异常,再捕获父类异常              
  
9、内联类
   把一个类写到另一个类的内部
   异常一般会做成内联类 A::exp ,靠前缀制定自己的命名空间  
   内联类,private修饰只能在本来中使用,对外是隐藏的,只有public 修饰的才能在外面使用
  
10、异常总结
   (1)检查错误的一种手段
   (2)可以用简单数据类型定义,还可以自定义类型
   (3)产生 throw e; 异常对象
        处理 try{}catch(异常类型){}  --- 异常类型要与throw抛出的一样
   (4)传播
  
11、银行项目 --- 面向对象
    需求分析的时候,要画用力图
    Biz Object 完成业务逻辑
    Value Object 操作数据(Account)
   
    Menu 收集用户信息,用户选择的业务
    Biz 针对某项业务收集信息
    DA  提供文件访问服务
    Account 保存数据

1、在头文件中
  #ifndef _ACCOUNT_   //预编译选项,表示如果没有定义这个宏
  #define _ACCOUNT_   //创建以_ACCOUNT_命名的宏
                        并声明类
  #endif                
 
2、链表
   (1)解决数组必须连续存储的问题
        链表是可以不连续的,通过每个节点的指针连接
   (2)节点中一部分空间用于存放数据,另一部分是一个指向下一个节点的指针       
   (3)每个节点都是一个结构
       struct node{
             int data;    //存储数据
             node* next;  //指向下一个节点的指针,是自己这个结构的类型
        }
   (4)尾节点 --- 链表中的最后一个节点 --- 指针指向NULL
        头节点 --- 要访问链表中的元素,必须要知道头节点的位置
                   把地址放在一个指针中 --- 头指针指向头节点,只是一个指针 --- 是必须存在的元素
   (5)对链表的常见操作 --- 增删改查
   (6)链表与数组的区别
        数组:空间必须连续,数组是定长的,插入和删除需要遍历整个数组,效率不高。
              取元素可直接使用下标,访问方便
        链表:空间在内存中不必连续,通过指针连接
              链表是不定长的,可以随时添加新节点,通过指针关联
              对链表的插入删除,不需要移动节点位置,只对指针操作即可
              访问元素,要从头指针开始遍历
             
        当数据需要频繁的插入删除的时候,需要使用链表
        当改动不大,查询频繁的时候,使用数组
        潜规则 : 能用数组就不用链表
       
        ======================================================================
                                      link.h
        ======================================================================
        #ifndef _LINK_
        #define _LINK_

using namespace std;

class Node{  //节点类
        public :
              int val;      //保存数据
              Node* next ;  //保存下一个节点的地址
              Node(){       //构造函数,把指针初始化为NULL
                 next = NULL;      
              }    
        };

class Link{
        protected :
             Node* head;   //头指针
        public :
             Link();
             ~Link();
             void insertTail(int);
             void insertHead(int);
             void del(int);
             int indexOf(int); //查询一个元素的下标
             void update(int , int);
             void disp();                   
        };

#endif 
       
        ======================================================================
                                  link.cc
        ======================================================================                                   
        #include "link.h"
        #include <iostream>
        using namespace std;

Link::Link(){
           head = NULL;            
        }

Link:: ~Link(){//释放空间,从头向尾释放
            if(head != NULL){
                Node *p = head;
                head = head->next; //把头节点向后移动
                delete p;          //抛弃原来的那个头节点
                cout << "delete one ... " << endl;
            }
        }
        //尾插入
        void  Link::insertTail(int v){
              Node *p = new Node;
              p->val = v;  
              if(head == NULL){
                   head = p;   //让新节点的指针指向新节点,即把新节点的地址保存在头指针中
                   return ;       
              }
              Node * temp = head ; //用一个临时指针,从头节点开始找到 尾
              while(temp -> next != NULL){  //表示temp不是尾节点
                   temp = temp -> next ; //用temp后面的一个指针为自己赋值,即指向下一个节点
              }
              temp -> next = p;  //尾插入,最后一个节点的指针保存新节点的地址
         }

//头插入
         void  Link::insertHead(int v){
               Node *p = new Node;  //创建新节点
               p->val = v ;         //保存数据
               p->next =  head;     //让新节点的指针和头指针一样指向第一个节点
               head = p;            //让头节点指向新节点
         }

void  Link::del(int v){   //找到被删除的节点 ,
               if(head == NULL ){
                     return ;       
               }
   
               if(head -> val == v){
                     Node *p = head;
                     head = head->next;
                     delete head;
               }        
    
               Node *p1 = head->next; //找值相同的一个
               Node *p2 = head ;      //跟在p1后面
               while(p1 != NULL){
                   if(p1->val == v){
                        p2->next = p1 -> next;
                        delete p1;
                        break;
                    }          
                    p1 = p1->next;
                    p2 = p2->next; 
               }
          }
         
          int  Link::indexOf(int v){ //查询一个元素的下标
               Node * p = head ;
               int counter = 0 ;
               while( p != NULL ){
                   if( p->val == v ){
                       return counter ;
                    }
                    p=p->next ;
                    counter++ ;
               }
               return -1 ;    
           }

void  Link::update(int v1 , int v2){
                Node * p = head ;
                while( p != NULL ){
                      if( p->val == v1 ){
                         p->val = v2 ;
                      }
                      p = p->next ;
                  }       
          }
          void  Link::disp(){
                 Node *p = head;
                 while(p != NULL){
                       cout << p->val << " " ;       
                       p = p->next;
                 }     
                 cout << endl;
          }

3、二叉树
   每个节点最多只有两个分支的树,它有一个根指针,要指向这棵树的根节点(最顶端的节点).
   左子树上的值小于其父节点的值,右子树上的值都大于其父节点上的值。    ---  排序二叉树
   (1)周游(遍历) :先序  ---  中左右
                       中序  ---  左中右    
                       后序  ---  左右中
   (2)非常方便查找

二叉查找树的常见操作:
1) 插入. 示例代码如下:
Node* Tree::_insert(int v, Node* r){  //真正实现插入操作,返回插入以后的根
    if(r == NULL){         //是一棵空树 (空子树)
        Node* p = new Node(v); //创建新节点
        r = p;                 //让新节点成为根或者子节点
        return r;
    }
    if( v < r->val){  //插到左子树上
        r->left = _insert(v,r->left);
        return r;
    }else{            //插到右子树上
        r->right = _insert(v,r->right);     
        return r;
    }
}

2) 查找. 示例代码如下:
    Node* & find( bnode* & root, const DATA& cd )
    {
        if( root==NULL )                    // 如果root节点是空,则为空树
            return root;                    // 返回root指向的地址,即NULL
        else if( root->data==cd )           // 如果root节点就是要查找的数值
            return root;                    // 返回root指向的地址,为了清晰,和上面的分开写
        else if( cd < root->data )          // 如果root节点指向的值大于要查找的值
            return find( root->left, cd );  // 返回查找root的左子树返回的地址
        else
            return find( root->right, cd ); // 否则返回查找root的右子树返回的地址
    }
           
3) 删除. 示例代码如下:
   被删除的是树根(1)则选择右子树的树根做新树根,左子树可以整个挂在右子树最左侧的一个左节点上
                      右子树中最左边的一个节点,是最靠近左子树的树根的     
                 (2)让左子树中的最大节点做新树根
                
Node* _del( int value , Node* r ){
  if( r == NULL ){       //删除空树
   return r ;
  }
  if( r->value == value ){        //删除树根
       if(r->left==r->right){      //左右子树都是NULL的情况下
          delete r ;
            return NULL;
        }else if( r->right == NULL ){  //只有右子树,没有左子树的时候
          Node * p = r;
         r = r->left ;
         delete p ;
         return r ;
      }else if( r->left == NULL ){   //只有右子树,没有左子树
          Node *p = r ;
         r=r->right ;
         delete p ;
         return r ;
      }else{                          //左右子树都有
         Node * p1 = r -> right ;
         Node * p2 = r -> right ;
         while( p2->left != NULL ){
            p2 = p2->left ;
         } 
         p2->left = r->left ; 
         delete r ;
         return p1 ;
      } 
    }

if( value <= r->value ){
     r->left = _del( value , r->left);
     return r ;
  }else{
     r->right =_del( value, r->right );
     return r ;
  } 
  return r ;
}

作业:修改链表程序,能够删除全部相同元素;在指定位置后插入数据

1、算法
    脱离具体的语言
    有穷性 --- 在保证执行有限步骤之后确定能够结束
    确切性 --- 每条语句具体干什么
    输入输出 --- 所有的算法都有输出,打印屏幕,写文件,写DB
   
2、快速排序法
   数据个数超过一个,任选其中一个数据作为分界值,把其他数据按大小关系分为2组,分界值在中间
   对两组数据实行递归重组
  
   //快速排序算法,效率最高的排序算法。第一个参数表示数组首地址,第二个参数表示数组起始位置,第三个参数表示结束位置
   void mysort( int * p , int left , int right ){
         int l = left ;     //从左侧开始走
         int r = right ;    //从右侧开始走
         int povit = p[(left + right)/2];  //把数组中间的一个数据作为分界点
         do{
               while( p[l]<povit && l < right ){   //循环退出,则是l找到一个比自己大的
                  l++ ;
               }
               while( p[r]>povit && r > left ){
                   r--;
              }
  
              if( l <= r ){
                   int t = p[l];
                   p[l] = p[r];
                   p[r] = t ;   
                   l++;
                   r--;
              }
          }while( l <= r );   //条件就是左右的两个人还没有碰面
         
          if( r > left ){      //只要右边的仍比左边的大,就要继续循环
             mysort( p , left , r );     
          }

if( l < right ){      //只要左边的仍比右边的小,也要继续循环
              mysort( p , l , right );
           }
     }   
    
3、直接使用系统的qsort()函数
   要自己定义一个排序规则  
  
4、模版
  (1)模版的参数至少出现一次,才能确定类型
  (2)只能在紧跟的函数中使用,函数声明紧跟在后面
       声明多个模版类型  template<class T1 , class T2>    
       class关键字不能省略
  (3)对于模版类型的要求,要能重载">","<","="
       建议:在编码时能用一种运算符完成的操作,就不要使用多个运算符,避免多个重载
  (4)用模版写的函数叫函数模版
          函数模版在调用的时候确定类型的
       用模版写的类叫类模版
          数据类型,参数类型,函数返回类型都可以使用模版
         
       类模版不是类,是不完整的类
       类模版要在声明时用类名<int>指定,确定类型
      
  (5)C++的泛型(模版)是编译时确定类型的 --- 效率             
       Java的泛型是运行时的
      
  (6)模版类的声明和定义(多文件结构)是不能分开的
       模版函数的声明和定义是可以分开的   template<class T> 在头文件和实现文件中都要出现
      
5、STL包含三大类,容器类(可以存储其他对象的对象),算法(一系列封装好的函数),迭代器(用于遍历操作的类)
     容器可以直接存储对象,也可以存储对象的指针。成熟的程序员喜欢使用间接存储。
     容器主要包括两种类型:序列类(一般是线形存储)和关联类(一般是非线性存储)。

vector  ----   数组  可变长   不提供pop_front()删除头元素的函数
      list      -----  链表
     
      (1)Vector    v[1000]当越界的时候,会出现段错误
                               v.at(1000) 越界的时候,会抛出out_of_range的异常,在程序中捕获
                               v.size()  返回长度,可利用这个循环迭代
                               v.empty()判断容器是否为空
                              
                               Iterator迭代器  : 可以做取*操作   *iterator
                                                              iter->name  <=> (*iter).name
                                                              iter++
                                                             
                               v.begin()  指向数组的开始
                               v.end()      指向数组最后一个元素的后面,是一个结束标志
                              
                               vector<int> v1;
                              vector<int>::iterator it;         //iterator是vector的一个内部类
                              for( it = v1.begin(); it != v1.end(); it++ )
                                            cout << *it << endl;

v.insert(iter,5);            //在iter所指的元素前面插入5
                               v.insert(iter,5,100);    //在iter所指的元素前插入5个100
                               这样的插入操作,会造成原来的iterator失效,对起重新赋值,可以保证继续使用
                              
      (2)list
               不能做at()
               多了push_front(),pop_front()
               iter不能做加n操作
               使用于做频繁的插入删除操作
              
6、关联式容器
    (1)map
            适合根据键查找值的操作   
            存储上按照键值排序 ,并且key值唯一
           
             map<int,Student> m;

Student s( 1 ,"liucy" );
           m.insert( map<int,Student>::value_type(
                        s.getId() , s )  ) ;              //创建一个pair,并存到map的第一个位置中    value_type是map的静态函数

Student s2( 4, "tangliang" );
          m.insert( map<int,Student>::value_type(
                        s2.getId() , s ) ) ;

map<int,Student>::iterator it ;
         for(it=m.begin();it!=m.end();it++ ){
               cout<< it->first << " "<<it->second;
               cout<<endl ;
         }                                         
                                                       
              在map中用[]查询,并不安全
              m.find(1);   // 查询key为1的value
              返回一个iter,指向找到的那个键值对,如果没找到,iter会与iter.end()的值相等
             
     (2)multimap
            其中的key允许重复
            查找:multimap<int ,Student>::iterator it ;
                    multimap<int ,Student>::iterator lt ;
                    multimap<int ,Student>::iterator ut ;

lt = m.lower_bound( 1 );
                  ut = m.upper_bound( 1 );

for( it=lt ; it != ut ; it++ ){
                             cout<<it->first <<" " ;
                            cout<<it->second <<endl; 
                 }   
                
     (3)set
               set中不能插入重复数据,相当于map中的key
               插入数据的时候不必指定位置
               因为与map中的key一致,仍保留着排序的特性
              
     (4) multiset
               与vector类似,唯一不同的就是保留着排序的特性
              
7、模版的声明和实现都写在头文件中
     /usr/local/include/c++/3.2/

C++笔记 5的更多相关文章

  1. git-简单流程(学习笔记)

    这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. NET Core-学习笔记(三)

    这里将要和大家分享的是学习总结第三篇:首先感慨一下这周跟随netcore官网学习是遇到的一些问题: a.官网的英文版教程使用的部分nuget包和我当时安装的最新包版本不一致,所以没法按照教材上给出的列 ...

  7. springMVC学习笔记--知识点总结1

    以下是学习springmvc框架时的笔记整理: 结果跳转方式 1.设置ModelAndView,根据view的名称,和视图渲染器跳转到指定的页面. 比如jsp的视图渲染器是如下配置的: <!-- ...

  8. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  9. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  10. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

随机推荐

  1. hmac库 密钥相关的哈希运算消息认证码

    # -*- coding: cp936 -*- #xiaodeng #python 2.7.10 #HMAC是密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一 ...

  2. PHP-九个非常有用的功能[转]

    1. 函数的任意数目的参数你可能知道PHP允许你定义一个默认参数的函数.但你可能并不知道PHP还允许你定义一个完全任意的参数的函数下面是一个示例向你展示了默认参数的函数:// 两个默认参数的函数fun ...

  3. HDUOJ----4509湫湫系列故事——减肥记II

    湫湫系列故事——减肥记II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  4. HDUOJ-------(1022)Train Problem I

    Train Problem I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  5. leetcode16 3-Sum

    题目链接 给定数组a[](长度不小于3)和一个数字target,要求从a中选取3个数字,让它们的和尽量接近target. 解法:首先对数组a进行排序,其次枚举最外面两层指针,对于第三个指针肯定是从右往 ...

  6. leetcode185 Department Top Three Salaries

    Employee表存储员工姓名.员工所在公寓.员工工资 Department表存储公寓id 评选出各个公寓的工资前三名的员工. 遇到的问题如下: limit,in等语句不能用在嵌套select语句中, ...

  7. 谈谈CListCtrl如何调整行高

    原文链接: http://blog.csdn.net/sstower/article/details/9094939 调整CListCtrl 行高通常有3种方法: 1.设定字体2.设定图片3.处理Me ...

  8. CentOS7 安装配置DNS服务器

    一.安装 yum install bind 二.配置 1. /etc/named.conf // // named.conf // // Provided by Red Hat bind packag ...

  9. (LeetCode)旋转数组

    原体描写叙述例如以下: Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3 ...

  10. jenkins 批量修改配置文件

    jenkins 批量修改配置文件   jenkin job 修改配置 修改前配置 <runPostStepsIfResult> <name>FAILURE</name&g ...