2018年物联网院科协计算机项目部第四次培训总结

计项部第四次培训总结

  1. 写在前面
  2. 输出中间变量的调试方法
  3. C++函数的重载
  4. STL模板库两个容器的初步认知
  5. 对树的初步认识

一、我们为什么要学算法

       算法是重要的。但是算法毕竟还需要依赖于一门语言实现,它并不纯是理论,并不能跟“数学竞赛”等同。它具有一定的工程性,明白一类算法的思想,并不一定能写出这类算法的程序,而且,对算法理论和程序精通的人,把这种精髓用到实际工程中,也是需要学习锻炼的。所以说,竞赛之人需要酌其轻重,不然可能会适得其反。
       所以很多人会觉得,算法除了在ACM竞赛中用到,平时几乎接触不到,把算法看做是一门“不食人间烟火”的东西。认同这种观点的人,并不少有。而产生这种观点的原因,可能就在于算法的“门槛”之高,算法的“内容”之难。
       其实不然。上述仅仅是从狭义上面说的。在广义上面,ACM算法只是算法中的一小部分。还有其他的包括机器算法、人工智能算法、大数据算法等等。可以说,算法是计算机科学的核心内容。没学过算法,没掌握过算法的程序员,不能说他十分有能力。只懂得招式,而没有内力,是成不了武林高手的。

二、输出中间变量的调试方法

1、调试的大体思想

       我们在培训第一讲里面说到了怎样用 codeblocks 的 debug 板块对我们的程序进行调试,通过一行一行的操作,我们可以通过顶栏的 debug - debug windows - watches 反馈窗格看到我们程序运行中各个变量的状态。
       但是很多时候调试的过程并不如人意。本来去寻找错误之处就是一件 麻烦的事情 ,而我们的代码不会一直只是一二十行,我们定义和需要考虑的变量也会渐趋于复杂。我们很多时候思考出的,想要快速获取我们想要的 数值过程,慢慢的调试会显得 冗长不清晰 。所以在这次培训里推荐大家用直接输出中间变量的方法去直接获取自己想要什么,这更有助于理清自己的思路,有效率地“修复”错误代码。

2、举个栗子
在这里插入图片描述
       就比如这一道简单的小题目,我们如果在写的时候出现了问题,就可以用某一种方式去输出自己想要的信息:

#include <iostream>
#include <stdio.h>

using namespace std;

int main()
{
    int s;
    while(cin>>s)
    {
        char num[8];
        getchar();
        char read;
        int i = 0;
        while((read = getchar()) != '\n')
        {
            num[i] = read;
            i++;
        }
        if(s == 0 && num[0] == 48)break;
        char show[2*s+3][i*(s+2)+i-1] = {};
        for(int j=1; j<=i; j++)
        {
            int temp = num[j-1] - 48;
            for(int k=0; k<s; k++)
            {
                if(temp == 4 || temp == 5 || temp == 6
                   || temp == 8 || temp == 9 || temp == 0)
                {
                    //cout<<"左上:"<<"show["<<k+1<<"]["<<(j-1)*(s+3)<<"]"<<endl;
                    show[k+1][(j-1)*(s+3)] = '|';//左上
                }
                if(temp == 2 || temp == 6
                   || temp == 8 || temp == 0)
                {
                    //cout<<"左下:"<<"show["<<k+s+2<<"]["<<(j-1)*(s+3)<<"]"<<endl;
                    show[k+s+2][(j-1)*(s+3)] = '|';//左下
                }
                if(temp != 5 && temp != 6)
                {
                    //cout<<"右上:"<<"show["<<k+1<<"]["<<s+1+(j-1)*(s+3)<<"]"<<endl;
                    show[k+1][s+1+(j-1)*(s+3)] = '|';//右上
                }
                if(temp != 2)
                {
                    //cout<<"右下:"<<"show["<<k+s+2<<"]["<<s+1+(j-1)*(s+3)<<"]"<<endl;
                    show[k+s+2][s+1+(j-1)*(s+3)] = '|';//右下
                }

                if(temp != 1 && temp != 4)
                {
                    //cout<<"上:"<<"show["<<0<<"]["<<k+1+(j-1)*(s+3)<<"]"<<endl;
                    show[0][1+k+(j-1)*(s+3)] = '-';//上
                }
                if(temp != 1 && temp != 7 && temp != 0)
                {
                    //cout<<"中:"<<"show["<<s+1<<"]["<<k+1+(j-1)*(s+3)<<"]"<<endl;
                    show[s+1][1+k+(j-1)*(s+3)] = '-';//中
                }
                if(temp != 1 && temp != 4 && temp != 7)
                {
                    //cout<<"下:"<<"show["<<2*s+2<<"]["<<k+1+(j-1)*(s+3)<<"]"<<endl;
                    show[2*s+2][1+k+(j-1)*(s+3)] = '-';//下
                }
            }
        }
        for(int j=0; j<(2*s+3); j++)
        {
            for(int k=0; k<(i*(s+2)+i-1); k++)
            {
                cout<<show[j][k];
            }
            cout<<endl;
        }
    }

    return 0;
}

       比如说这里就用的是枚举的方式去观察每一个数字相对应的输出是否和想法中一致(调试代码如注释行),从而对整个程序进行调试和掌控。

三、函数的重载

       培训的时候本来没有准备讲重载函数的,但是函数的重载是一个很基础的板块,而因为这个大家基础不是很牢,我就没有继续讲函数模板的知识了,但是这样就存在一个遗憾,因为STL模板库就是建立在其之上的,所以之后给大家也只是很简单的介绍了两个容器。因为学习要循序渐进,知其然亦要知其所以然,所以就不拓展更多的东西了,希望大家能消化消化这次的内容。

重载有csdn写的很成熟了,我这里就偷个懒。
https://blog.csdn.net/zhanghow/article/details/53588458 这篇主要是写遇到不同数据类型的函数的时候,是怎样实现重载的,讲得比较透彻,可以去看一眼(这篇里内容很少很简单)

四、容器

1、不定长数组 vector < >

头文件:#include <vector>
常用成员函数:
在这里插入图片描述

       对于vector的声明大体有下面几种方式:

vector<int> v1; //创建空的数组容器v1
vector<int> v2(v1); //新建数组容器v2并将数组v1的值拷贝给v2
vector<int> v3(k); //创建长度为k的容器v3
vector<int> v4(m,n);//创建长度为m的,初始值都为n的容器v4

       为了能更好的理解各个成员函数的使用,下面就是对上面各个函数的很简单的应用:

#include <iostream>
#include <vector>

using namespace std;

vector <int> c;
int main()
{
    cout<<"初始数据:"<<endl;
    for(int i=0; i<10; i++)
    {
        c.push_back(i);
    }
//    for(int i=0; i<10; i++)
//    {
//        int temp;
//        cin>>temp;
//        c.push_back(temp);
//    }
    for(std::vector<int>::iterator i = c.begin(); i != c.end(); i++)
    {
        cout<<*i<<" ";
    }
    cout<<endl;
    cout<<"size of c is:"<<c.size()<<endl;

    cout<<"删了一个:"<<endl;
    c.pop_back();
    for(std::vector<int>::iterator i = c.begin(); i != c.end(); i++)
    {
        cout<<*i<<" ";
    }
    cout<<endl;
    cout<<"size of c is:"<<c.size()<<endl;

    cout<<"头数据为:"<<endl;
    cout<<c.front()<<endl;
    cout<<"尾数据为:"<<endl;
    cout<<c.back()<<endl;

    cout<<"清除操作:"<<endl;
    c.clear();
    cout<<"size of c is:"<<c.size()<<endl;
    return 0;
}

       上面的程序里还有一点要说的就是迭代器iterator。迭代器类似于C语言里面的指针类型,在这里它提供了对数组元素进行快速随机访问以及在序列尾部进行快速插入和删除操作的功能。

2、映射 map

map的功能:

  1. 自动建立Key - value的对应。key 和 value可以是任意你需要的类型。
  2. 根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
  3. 快速插入Key - Value 记录。
  4. 快速删除记录
  5. 根据Key 修改value记录。
  6. 遍历所有记录。

       首先也是头文件#include <map>

       通常来说,定义一个新的map容器就直接用

map<int, string> your_function_name;

       定义map里对应的key值和value值的数据类型不是指定的,可以自行定义。

       为了更好的理解,给一个小栗子。
       输入数据包含了很多种不同的颜色(e.g : red, blue, orange)每个颜色可能有一个或者多个,想让你统计记录每种颜色各有多少个。
       代码如下:

#include <iostream>
#include <cstdlib>
#include <string>
#include <map>

using namespace std;

int main()
{
    map<string,int> word_count;

    string word;

    while(cin >> word)
    {
        ++word_count[word];}

    map<string, int>::iterator iter; 

    for(iter = word_count.begin(); iter != word_count.end(); iter++)
    {
        cout << "[" << iter->first << "] = " << iter->second << endl;
    }

    return 0;
}

       仔细看完之后你会发现这要比不用键值对来得容易得多。

五、树

       在这里没有对大家提很高的要求,主要是让大家熟悉一下这种数据结构类型。以后碰到的时候心里不会出现畏惧的感觉==

1、树是什么

       在计算机科学中,树是一种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
它具有以下的特点:

  • 每个节点有零个或多个子节点(child)
  • 没有父节点(parent)的节点称为根节点
  • 每一个非根节点有且只有一个父节点
  • 除了根节点(root)外,每个子节点可以分为多个不相交的子树

P.S : 每一个节点的子枝数目不超过2的树我们就叫它作二叉树。

2、建树的基本操作:

       构造一个节点类:

class node
{
public://声明公有成员,如果不声明,会默认作private
	char data; //结点值
	node *lchild, *rchild;  //左孩子,右孩子结点
	//node *parent;    //父结点,起到可以回溯的作用,开始学树的时候也可以不用
};//类声明最后要有分号哦

用递归的思想建树:

void CreateBiTree(node *&T)
{
	//这里和培训的时候说的有一些不一样,主要是数组在这里不是很好描述,
	//就直接在建立每个节点的时候读入该节点的值。
	//假设“#”是代表“空”。
	char ch;
	cin >> ch;
	if (ch == '#')
		T = NULL;
	else
	{
		T = new node();
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值