美文网首页
C++学习(计蒜客)

C++学习(计蒜客)

作者: KevinCool | 来源:发表于2016-08-22 14:02 被阅读303次

    学习C++

    1. 斐波纳切数列

    斐波那契数列是一种非常有意思的数列,由 00 和 11 开始,之后的斐波那契系数就由之前的两数相加。用数学公式定义斐波那契数列则可以看成如下形式:
    ​Fn表示斐波那契数列的第n项,你能知道斐波那契数列中的任何一项吗?

    #include <iostream>
    using namespace std;
    int Fibonacci(int pos);
    int main(){
        int pos;
        cin >> pos;
        int value;
        value = Fibonacci(pos);
        cout << value << endl;
        return 0;
    }
    int Fibonacci(int pos){
        if (pos == 0){
            return 0;
        }else if (pos == 1){
            return 1;
        }
        else{
            return Fibonacci(pos - 1) + Fibonacci(pos - 2);
        }
    }```
    
    ###2. 矩阵翻转
    晓萌最近在做一个翻转图片的应用,你可能也知道,图片其实是由一个个的点组成的。于是,晓萌想先做一个可以翻转矩阵的程序,来解决他问题的核心部分。
    输入第一行包括由空格分开的整数M、N、T(0 < M < 200,0 < N < 200,T=0或1),其中M和N分别表示待处理矩阵的行数与列数,T为0时表示左右翻转,为1时表示上下翻转。
    之后的M行,每行包括由空格分隔的N个整数,依次为输入矩阵的每一行的数据。
    输出包括M行N列,每个数字之间用一个空格分隔,每一行行末均有一个空格,表示的是按照要求翻转后的矩阵。
     
    

    include <iostream>

    using namespace std;
    int main(){
    int row,col,lrud;
    cin >> row >> col >> lrud;
    int arr[row][col];
    //i不能到5
    for (int i=0; i<row; i++){
    for(int j=0; j<col; j++){
    cin >> arr[i][j];
    }
    }
    //左右翻转
    if (lrud == 0){
    for (int i1=0; i1<row; i1++){
    for (int j1=col-1; j1>=0; j1--){
    cout << arr[i1][j1] << " ";
    }
    cout << endl;
    }
    }else if(lrud == 1){ //上下翻转
    for (int i1=row-1; i1>=0; i1--){
    for (int j1=0; j1<col; j1++){
    cout << arr[i1][j1] << " ";
    }
    cout << endl;
    }
    }
    }

    ###3. 位操作
    

    include<iostream>

    using namespace std;
    int main(){
    int a;
    cin>>a;
    //hex指输出16进制数,oct是八进制数,dec是十进制,bin二进制
    cout << hex << a << " " << ~a << endl;
    return 0;
    }```

    4. cstdio库

    #include <cstdio>引入C风格的输入和输出,scanf和printf比cout和cin要高效。

    5. 指针

    一个指针是一个地址,是一个常量,而一个指针变量却可以被赋予不同的指针值,是变量。定义指针的目的是通过指针去访问内存单元。
    指针变量的赋值只能被赋予地址数据,错误赋值将无法通过编译或者在运行中出错。变量的地址是系统分配,使用&进行取地址,*是指针运算符,间接访问运算符,通过指针变量存储的地址来访问变量。

    #include<iostream>
    using namespace std;
    int main(){
        int a = 0, b = 0, *p, *p1, *p2;
        cin >> a >> b;
        p1 = &a;
        p2 = &b;
        if (a<b){
            p = p1;
            p1 = p2;
            p2 = p;
        }
        cout << "a=" << a << ",b=" << b << endl;
        cout << "max=" << *p1 << ",min=" << *p2 << endl;
        return 0;
    }```
    函数的形式参数是一个指针类型的变量,*表示指针变量的类型声明,square函数中的指针指向了主函数中的变量,square函数中的指针值的运算将改变主函数中变量num的值。
    

    include<iostream>

    using namespace std;
    void square(int *n){
    *n = *n * *n;
    }
    int main(){
    int num = 2;
    cout<<"The original number is "<<num<<endl;
    square(&num);
    cout<<"The new value of number is "<<num<<endl;
    return 0;
    }```

    6. 引用

    引用就是某一变量的一个别名,对引用的操作与对变量直接操作完全一样,定义引用的表示方法与定义指针类似,只是用&代替了*,例如int a,&ra=a,ra是目标引用名,ra=1;等价于a=1,并且&只是在声明的时候起标识作用,不同于取地址。
    声明一个引用,不是新定义了一个变量,它本身不是一种数据类型。
    不能建立引用的数组,无法建立一个由引用组成的集合,但是可以建立数组的引用。
    下面是引用做函数参数的例子,同样和指针一样可以修改main中的变量值。

    #include<iostream>
    using namespace std;
    void square(int &n){
        n = n * n;
    }
    int main(){
        int num = 2;
        cout<<"The original number is "<<num<<endl;
        square(num);
        cout<<"The new value of number is "<<num<<endl;
        return 0;
    }```
    ###7. 内存分区
    计算机中的内存在用于编程的时候,被人为的进行了分区,分为栈区stack,堆区heap,全局区(静态区Static),文字常量区,程序代码区。
    函数的参数值,局部变量值都被存在了栈区,这部分的内存是系统帮助来进行管理的。
    堆区的内存,是由程序员来进行分配和释放的,使用堆内存的原因是栈上内存较少,不够用,系统管理内存的方式比较死板,不方便用。堆上的内存,程序员手动分配后,如果不释放就有可能出现内存泄漏。
    全局变量和静态变量的存储是在一块的,初始化的全局变量和静态变量在一块区域,为初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
    文字常量区用于储存常量字符串的,程序结束后由系统释放。
    程序代码区用于存放函数体的二进制代码。
    `int *arr = new int[n];` new用于申请堆上空间的运算符,申请空间的最开始位置首地址,用前面声明的指针进行指向,从而可以像用数组一样用指针名使用这块空间。
    

    include<iostream>

    using namespace std;
    int main(){
    int i,n;
    cin>>n;
    int *arr= new int[n];

    //以下代码对一个数组第一位进行了赋值
    arr[0]=1;
    
    //以下代码对一个长度为n的数组第二位开始依次做计算,并输出最后一个值结果
    for(i=1;i<n;i++){
        arr[i]=arr[i-1]+i;
    }
    cout<<arr[n-1];
    //请在下一行释放内存空间
    delete []arr;
        arr = NULL;
    return 0;
    

    }```
    new来动态申请分配堆内存
    申请单个对象

    int *p;
    p = new int;
    //或者申请的堆内存中直接包含值
    int *p;
    p = new int(100);```
    动态申请数组
    

    int *p;
    p = new int[n];```
    圆括号是用来赋初值的,方括号是用来说明申请堆空间大小的。
    内存释放
    delete加指针名的形式进行释放,如果指针指向的空间是数组,那么需要在delete后加上[]进行标识。然后将arr指针数组指向NULL,使之成为空指针。

    8. 链表

    #include <iostream>
    using namespace std;
    
    struct List
    {
        int num;
        List *next;
    };
    
    List *head;
    
    void Insert(List *&head)
    {
        //在下面编写插入代码
        List *node = NULL;
        node = new List;
        cin >> node->num;
        node -> next = NULL;
        List *q, *p;
        //如果插入的值本身小于head的值,插入到最前面
        if(node->num <= head->num){
            node->next = head;
            head = node; 
            return ;
        }
        p = head; //记录head指针
        q = head->next; //记录指向head后面的
        while(q!=NULL){
            if(node->num > q->num){
                //大于的话,判断下一个
                p = q;
                q = q->next;
            }else{
                break;
            }
        }
        p->next = node;
        node->next = q;
    }
    void deleteNode(List *&head)
    {
        //在下面编写删除代码
        int num;
        cin >> num;
        List *p = NULL, *q = NULL;
        p = head;
        if(p->num == num){
            head = p->next;
            delete p;
            return;
        }
        //如果删除的节点不是头节点
        q = p->next;
        while(q != NULL){
            if(q->num == num){
                p->next = q->next;
                delete q;
                return;
            }
            if(q->num > num){
                return;
            }
            p = q;
            q = q->next;
        }
        return ;
    }
    List *Create()
    {
        List *p = NULL;
        List *q = NULL;
        head = NULL;
        for ( int i = 0; i < 3; i++ ) {
            p = new List;
            p->num = i * 2;
            if ( head == NULL ) {
                head = p;
            }
            else {
                q->next = p;
            }
            q = p;
        }
    
        if ( head != NULL ) {
            q->next = NULL;
        }
    
        return head;
    }
    
    void displayList(List *head)
    {
        while ( head != NULL ) {
            cout << head->num;
            head = head->next;
            if ( head != NULL ) {
                cout << "->";
            }
        }
        cout << endl;
    }
    
    int main() {
        Create();
        Insert(head);
        displayList(head);
        return 0;
    }```
    ###9. 单链表部分逆置
    给定一个固定的单链表,输入两个数begin和end。将下标为begin到end之间的内容逆置。
    
    给定的单链表为:0->2->4->6->8->10->12->14->16->18
    
    测试数据确保begin和end不会超出单链表的长度范围,并且end>=begin
    

    include <iostream>

    using namespace std;

    struct List
    {
    int num;
    List *next;
    };

    List *head;

    void reverse(int begin, int end, List *&head)
    {
    //在这个函数中编写你的代码
    if(end <= begin || begin < 0 || end > 9){
    return;
    }
    if(begin == 0){
    List *p = head;
    List *qian = p;
    List *kai = p;
    List *hou = NULL;
    p = p->next;
    for(int i=1;i<=end;i++){
    hou = p;
    p = p->next;
    //开始转换
    hou->next = qian;
    qian = hou;
    if(i == end){
    kai->next = p;
    head = hou;
    }
    }
    }else{
    //记录begin前面的指针,begin的指针,end处的,end后面的
    //算法思想就是将链表指针逆过来
    List *p = head;
    //q 开始的前一个节点指针
    List *q = NULL;
    //qian 是两个节点进行逆序时第一个节点指针
    //kai 是开始位置节点指针
    //hou是逆序时候第二个节点指针
    List *qian=NULL, *hou=NULL, *kai=NULL;
    for(int i=0;i<=end;i++){
    if(i == begin - 1){
    q = p;
    qian = p;
    p = p -> next;
    }else if (i >= begin){
    if (i == begin){
    kai = p;
    }
    hou = p;
    p = p->next;
    //这里进行两个节点之间的逆序
    hou -> next = qian;
    qian = hou;
    if(i == end){
    if(q == NULL){
    head = hou;
    }else{
    //这里处理结束时候与链表其它位置交接的地方
    q->next = hou;
    kai->next = p;
    }
    }
    }else{
    p = p->next;
    }
    }
    }
    }

    List *Create()
    {
    List *p = NULL;
    List *q = NULL;
    head = NULL;
    for ( int i = 0; i < 10; i++ ) {
    p = new List;
    p->num = i * 2;
    if ( head == NULL ) {
    head = p;
    }
    else {
    q->next = p;
    }
    q = p;
    }

    if ( head != NULL ) {
        q->next = NULL;
    }
    
    return head;
    

    }

    void displayList(List *head)
    {
    while ( head != NULL ) {
    cout << head->num;
    head = head->next;
    if ( head != NULL ) {
    cout << "->";
    }
    }
    cout << endl;
    }

    int main() {
    Create();
    int begin, end;
    cin >> begin >> end;
    reverse(begin, end, head);
    displayList(head);
    return 0;
    }```

    10. 单链表是否有环?

    如果单链表里有重复的节点,则说明单链表中存在环
    有一个链表,我们需要判断链表中是否存在环。有环则输出true,否则输出false。

    输入有多行,每行为由空格分隔的两个整数m和n,m是当前结点的数据,n代表当前结点的指针域指向第n个结点。

    n存在四种情形:
    ①为-1,代表该结点的指针域指向NULL,输入结束;
    ②指向该结点之前的结点,如第3个结点的指针域指向n = 2的结点;
    ③指向自己,如第3个结点的指针域指向n = 3的结点;
    ④指向其直接后继结点,如第3个结点的指针域指向n = 4的结点,不能指向n = 5的结点。

    当输入为:
    1 2
    2 3
    3 -1
    时,代表:第1个结点的数据为1,指向第2个结点;第2个结点的数据为2,指向第3个结点;第3个结点的数据为3,指向NULL,输入结束。
    下面是代码实现一个初步的算法,基本思想还是建立链表后,进行遍历,遍历过的节点置flag为1,如果以后遍历到flag==1的节点,那么就说明有环。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct List{
        int num;
        int flag;
        List *next;
    };
    
    //建立头指针
    List *head = NULL;
    
    int main(){
        //建立输入动态数组
        vector<int> data;
        vector<int> pos;
        vector<List *> point;
        int m, n;
        while(cin >> m >> n){
            data.push_back(m);
            pos.push_back(n);
        }
        for(int i=0;i<pos.size();i++){
            List *node = NULL;
            node = new List;
            node->num = data[i];
            node->flag = 0;
            point.push_back(node);
        }
        head = point[0];
        //建立链表
        for(int j=0;j<pos.size();j++){
            if(pos[j] != -1){
                point[j]->next = point[pos[j]-1];
            }else{
                point[j]->next = NULL;
            }
        }
        //遍历链表
        int loop = 0;
        List *p;
        head->flag = 1;
        cout << head->num << "->";
        p = head->next;
        while(p){
          if(p->flag != 1){
            cout << p->num << "->";
            p->flag = 1;
          }else{
            loop = 1;
            break;
          }
          p = p->next;
        }
        cout << endl;
        if(loop == 1){
          cout << "true" << endl;
        }else{
          cout << "false" << endl;
        }
    }```
    ###11. 面向对象Object Oriented Programming
    首先是抽象特性,封装,继承,多态
    C++对于类内的成员提供了三种访问权限,public,protected,private表示公有,保护和私有。
      - public
    表示其后定义的成员对程序所有部分可见,包括数据成员,成员函数以及类型。作为公有成员存在的大多是一些特定方式读取,修改数据成员的成员函数,类的接口。
      - private
    修饰成员时表示该成员仅在该类内可见,类外无法对这个成员进行访问。包括大部分变量,一些不需要类的使用者关注的用于具体运算过程的函数。
      - protected
    继承派生
    
      通过对成员访问的控制,信息被封存在了一个可控的地方,可以设定一些安全的途径,获得和修改一些信息,这就是面向对象的一个特性,封装
    

    include<iostream>

    using namespace std;
    class Student{
    private:
    int id;
    int age;
    public:
    int getID(){return id;}
    int getAge(){return age;}
    //先进行声明,函数比较复杂,定义在类的外面
    void setID(int newID);
    void setAge(int newAge);
    };
    void Student::setID(int newID){
    id = newID;
    }
    void Student::setAge(int newAge){
    age = newAge<100?newAge:99;
    }
    int main(){
    Student tom;
    tom.setID(1);
    tom.setAge(16);
    cout<<tom.getID()<<" "<<tom.getAge();
    return 0;
    }```

    相关文章

      网友评论

          本文标题:C++学习(计蒜客)

          本文链接:https://www.haomeiwen.com/subject/ctfgsttx.html