C with STL学习笔记

字符串(string)

ASCII编码

#include
#include

using namespace std;

int main(){
    for(int i = 0; i < 128; i++) printf("%d: %c\n", i, (char)i);
    return 0;
}
//'A'~'Z'为65~90; 'a'~'z'为97~122; '0'~'9'为48~57

因此字符可以当成整数进行算术运算

int a = 'B' - 'A';//a = 1
char c = 'A' + 2; //输出c为'C'

字符串的输入与输出

  • char* fgets(char*str, int n, FILE*stream)fgets从指定的流stream读取一行,并把它储存在str所指向的字符串内。当读取(n-1)个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止。
    PS:当输入一行字符串的末尾是换行符时,最后的换行符也会读入字符串str,fgets不会过滤回车
  • int puts(const char*str)把一个字符串写入标准输出stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。
    返回值:如果输出成功,该函数返回一个非负数为字符串长度(包括\0),如果发生错误则返回EOF。
  • getline(cin, string s)读取一整行字符串至字符串变量s
  • cin.getline(char [], int n)读取一行字符串至字符数组,当读取到n-1个字符(为空字符留空间)或换行符时停止读入。不会读入换行符
#include
#include

using namespace std;

int main()
{
    char s[100];
    fgets(s, 100, stdin);
    puts(s);

    return 0;
}

//输入 abc def
//输出abc def再加上换行
#include
#include

using namespace std;

int main(){
    char s[10];
    cin.getline(s, 10);
    cout << s << endl;
    string s1;
    getline(cin, s1);
    cout << s1 << endl;
}
//输入hello world 输出hello wor
//输入hello world 输出hello world

strcmp

int strcmp(const char*s1, const char*s2, size_t n) 按照字典序比较两个字符串,若返回0:s1=s2;1:s1>s2;-1:s1

#include
#include
int mycmp(const char *s1, const char *s2);
int main(int argc, char const*argv[]){
    char s1[] = "abc";
    char s2[] = "Abc";
    int i = (int *)'a';
    int j = (int *)'A';
    printf("strcmp(s1, s2)=%d\n", strcmp(s1, s2));
    printf("'a'=%d  'A'=%d\n", i, j);//'a'=97  'A'=65
    printf("%d\n", 'a' - 'A');
    printf("s1-s2=%d\n", mycmp(s1, s2));
}
//若要比较字符串差值,自己编写mycmp
int mycmp(const char*s1, const char*s2){
    int i = 0;
    while(1){
        if (s1[i]!=s2[i]){
            break;
        }else if(s1[i]=='\0'){
            break;
        }
        i++;
    }
/*输出为
strcmp(s1, s2)=1
'a'=97  'A'=65
32
s1-s2=32  */

strlen

size_t strlen(const char *str) 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。注意:这个函数的时间复杂度为O(n)

strcpy

char *strcpy(char *restrict dst, const *src)把src字符串拷贝到dst位置。restrict表示 src和dst不重叠,返回dst。我们也可以编写与strcpy功能相同的函数,如下:

#include
#include
char *mycpy(char *dst, char *src);
char *mycpy2(char *dst, char *src);
int main()
{
    char src[] = "hello";
    char *dst = (char *)malloc(strlen(src) + 1);//为dst指针分配空间
    //strcpy(dst, src);  //将src字符串复制到dst位置
    mycpy2(dst, src);//strcpy,mycpy,mycpy2运行结果相同
    printf("dst=%p\n", dst);
    int i;
    for (i = 0; i < strlen(src);i++){
        printf("%c", dst[i]);
    }
    printf("\n");
    free(dst);
}
//第一种:数组法
char *mycpy(char *dst, char *src){
    int i = 0;
    while(src[i]!='\0'){
        dst[i] = src[i];
        i++;
    }
    dst[i] = '\0';
    return dst;
}
//指针法
char *mycpy2(char *dst, char *src){
    char *ret = dst;
    while(*src != '\0'){ 
        *dst ++ = *src++;
    }
    *dst = '\0';
    return ret;
}
//while内部条件也可以写为*src,当*src为"\0"时终止循环.这是因为参与运算时字符型会转为整型,'\0'对应0

memset

void *memset(void *str, int c, size_t n)复制字符 c(一个无符号字符)到参数 str 所指向的字符串的后n个字节,比如赋值1,则a[0]=20+ 28+216+224=16843009
该函数返回一个指向存储区 str 的指针。

#include 
#include 
 
int main ()
{
   char str[50];
 
   strcpy(str,"This is string.h library function");
   puts(str);
 
   memset(str,'$',7);
   puts(str); //把一个字符串写入标准输出stdout,直到空字符,但不包括空字符,返回输出字符串的长度,包括结尾的0,如果发生错误则返回 EOF
   
   return(0);
}
//This is string.h library function
//$$$$$$$ string.h library function

memcpy

void *memcpy(void *str1, const void *str2, size_t n)从存储区 str2 复制 n 个字节到存储区 str1

#include 
#include 
 
int main ()
{
   const char src[50] = "http://www.runoob.com";
   char dest[50];
 
   memcpy(dest, src, strlen(src)+1);
   printf("dest = %s\n", dest);
   
   return(0);
}

标准库类型string

  • string的定义和初始化:
#include
#include

using namespace std;

int main()
{
    string s1;
    string s2 = s1; //s2是s1的副本
    string s3 = "hiya";//s3为字符串字面值的副本
    string s4(10, 'c'); //s4的内容是cccccccccc
}
  • 字符串的读写:
#include
#include

using namespace std;

int main()
{
    string s1;
    cin >> s1;
    cout << s1 << endl;
}
  • 处理string对象中的字符(两种方法)
#include
#include

using namespace std;

int main()
{
    string s1, s2;
    cin >> s1 >> s2;
    string s3 = s1 + ' ' + s2;
    
    for(int i = 0; i < s3.size(); i++) cout << s3[i] << endl;
    cout << endl;
    for(char c: s3) cout << c << endl;//c的地址与s3中元素地址是不同的
    for(char &c: s3) c = 'a';   //c前加&则与s3中元素地址相同,s3中元素全变为a
}

综合应用:

#include
#include

using namespace std;

int main()
{
    string s1, s2;
    cin >> s1 >> s2;
    string s3 = s1 + ' ' + s2;//做加法运算时,字面值和字符都会被转化成string对象,因此直接相加就是将这些字面值串联起来;当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符的两侧的运算对象至少有一个是string。
    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    printf("%s\n", s3.c_str());  //c_str返回存储s3字符串的字符数组的首地址
}
/*分别输入hello和world
hello world
hello
world
hello world
hello world   */

reverse(array exe3)

reverse函数功能是逆序(或反转),多用于字符串、数组、容器。头文件是#include
reverse函数用于反转在[first,last)范围内的顺序(包括first指向的元素,不包括last指向的元素),reverse函数无返回值

//用法示例
#include
#include
#include
using namespace std;

int main()
{
    vector<int> n = {1,2,3,4};
    reverse(n.begin(), n.end()); //翻转vector
    for(auto c:n) cout << c << ' ';
    cout << endl;

    int a[] = {1,2,3,4,5};
    reverse(a, a+5);
    for(auto c:a) cout << c << ' ';
    cout << endl;

    string s1 = "hello";
    string s2 = s1.substr(2,3);
    cout << s2<<endl;
    reverse(s1.begin(),s1.end());
    cout << s1 << endl;
}
/*
4 3 2 1 
5 4 3 2 1
llo
olleh           */
//练习题3:输入一个n,再输入n个整数。将这个数组顺时针旋转k(k <= n)次,最后将结果输出。
//利用算法库中的reverse函数
#include
#include
using namespace std;
int main()
{
    int k, n, array[100];
    scanf("%d", &n);
    scanf("%d", &k);
    for (int i = 0; i < n; i++){
        scanf("%d", &array[i]);
    }
    reverse(array,array+n);//对指针操作第二个参数是组后一个元素后面的那个指针
    reverse(array, array+k);
    reverse(array+k, array+n);
    for(int i = 0; i < n; i++){
        printf("%d\n",array[i]);
    }
}

substr(acwing 773)

s.substr(pos, n)拷贝字符串,包含从s的pos下标到n-1处的字符

/*有两个不包含空白字符的字符串 str 和 substr,str 的字符个数不超过 10,substr 的字符个数为 3。(字符个数不包括字符串结尾处的 \0。)
将 substr 插入到 str 中 ASCII 码最大的那个字符后面,若有多个最大则只考虑第一个。

输入格式:输入包括若干行,每一行为一组测试数据,格式为
str substr

输出格式:对于每一组测试数据,输出插入之后的字符串。  */
#include

using namespace std;

int main()
{
    string a, b;
    while(cin >> a >> b){
        char c = a[0];
        int max = 0;
        for(int i = 1; i < a.size(); i++){ //求出ASCII码最大元素的下标
            if(a[i] > c) {
                c = a[i];
                max = i;
            }
        }
    cout << a.substr(0, max+1) + b + a.substr(max+1) << endl;
    }
}

函数

PS:1.函数名称可以一样,只要参数类型不完全相同即可 2.函数参数可以有默认值,但需要把有默认值的参数写在后面

参数的传递

C++中可以传引用参数,当函数的形参为引用类型时,对形参的修改会影响实参的值。使用引用的作用:避免拷贝、让函数返回额外信息。

#include

using namespace std;

void f(int &x){
    x = 5;
}
int main()
{
    int x = 10;
    f(x);
    cout << x;  //输出5
}
#include
using namespace std;


int main()
{
    int a[4]={1,2,3,4};
    for(auto c:a) c = 0;
    for(int i = 0; i < 4; i++) cout << a[i] <<' ';
    cout << endl;
    for(auto &c:a) c = 0;
    for(int i = 0; i < 4; i++) cout << a[i] <<' ';
}
//1 2 3 4
//0 0 0 0

多维数组的形参写法

多维数组中,除了第一维之外,其余维度的大小必须指定
void print(int (*a)[10]) {/* … */}
void print(int a[][10]) {/* … */}

#include

using namespace std;
void print(int n, int m, int (*a)[3]){  //注意要加小括号,不然表示指针数组
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m ; j++) cout << a[i][j] << ' ';  //若在函数内部给数组赋值,数组的值将变化
        cout << endl;
    }
}
int main()
{
    int a[3][3] = {
        {1,2,3},
        {4,5,6},
        {7,8,9}
    };
    print(3,3,a);
}
//打印出a矩阵

函数递归(重点复习acwing 822和823)

//求阶乘
#include

using namespace std;
int fac(int n){
    if(n == 1) return 1;
    return n*fac(n-1);
}

int main()
{
    int n;
    cin >> n;
    cout << fac(n);
}
//输入6,输出720

类和结构体

类中的变量和函数被统一称为类的成员变量。private后面的内容是私有成员变量,在类的外部不能访问;public后面的内容是公有成员变量,在类的外部可以访问。具体应用如下:

#include

using namespace std;
const int N = 10000;

class Person
{
    private:
        int age, height;
        double money = 0;
        string books[100];
    public:
        string name;
        void say()
        {
            cout << "I'm" << ' ' << name << endl;
        }
        int set_age(int a)
        {
            age = a;
        }
        int get_age()
        {
            return age;
        }
        void add_money(double x)
        {
            money += x;
        }
        double get_money()
        {
            return money;
        }
};
int main()
{
    Person c;
    c.name = "wzz";     //正确!访问共有变量
    c.say();
    //c.age = 18        //错误!访问的是私有变量
    c.set_age(18);      //正确,set_age()是共有成员变量
    cout << c.get_age() << endl;  //输出18
    c.add_money(100.0);
    cout << c.get_money() << endl; //输出100
}

结构体

结构体和类的作用是一样的。不同点在于类默认是private,结构体默认是public。结构体的初始化方法如下

//方法一 :构造函数
#include

using namespace std;

struct person{
    int age, height;
    double money;
    person(){};
    person(int _age, int _height) : age(_age), height(_height) {}  //这是定义构造函数的简单写法
    person(int _age, int _height, double _money){  //构造函数
        age = _age;
        height = _height;
        money = _money;
    }
};
int main()
{
    person p(18,180,100); 
    cout << p1.age;
    person p2(21,60);
    cout << p2.age << endl;
}
//注意:person变量p如果参数形式与构造函数不相同会报错,因此这个例子中如果不给p参数且没有person(){}时程序会出错
//方法2:直接赋值
#include

using namespace std;

struct person{
    int age, height;
    double money;
};
int main()
{
    person p1= {18,180,100};//这样可以对结构体初始化,未赋值的会初始化为0
    cout << p1.age;

}

链表的增删遍历

#include

using namespace std;

struct student{
    int score;
    student* next;
    student(int _score) : score(_score), next(NULL){} //构造函数
};

int main()
{
    student* s1 = new student(20); //new 创建新的结构体
    //student s2;//错误,结构体不存在默认的构造函数
    student* s2 = new student(30);
    student* s3 = new student(40);

    student* head = s1;
    s1->next = s2;
    s2->next = s3;
    //遍历链表中的所有元素
    for(student* i = head; i; i = i->next) cout << i->score << ' ';
    cout << endl;
    //删除给定值的节点
    student* i;
    student *j;
    int del_num;
    cin >> del_num;
    for(i = NULL, j = head; j; i = j, j = j->next){
        if(j->score == del_num){
            if(!i){
                head = j->next;
                free(j);
                break;
            } else{
                i->next = j->next;
                free(j);
                break;
            }
        }
        if(j->next == NULL) cout << "找不到指定值" << endl;
    }
    for(i = head; i; i = i->next) cout << i->score << ' ';
    cout << endl;
//在结尾添加50的节点
    student *p4 = new student(50);
    for(i = head; i->next; i = i->next) ;
    i->next = p4;
    for(student* i = head; i; i = i->next) cout << i->score << ' ';
    cout << endl;
}

/*运行结果
20 30 40 
30
20 40 
20 40 50  */

STL容器

vector

vector是变长数组,支持随机访问,不支持在任意位置O(1)插入。为了保证效率,元素的增删一般应该在末尾进行。vector是基于倍增的思想去实现动态空间增长,N个数存入vector只需要运行(N/2+ N/4 + )次,时间复杂度为O(n)

#include
#include
using namespace std;

int main()
{
    vector<int> a({1,2,3});
    a.push_back(4);
    for(auto c:a) cout << c << ' ';
    cout << endl;

    a.pop_back();
    a.erase(a.end()-1);   //vector中erase(const_iterator __first, const_iterator __last)

    for(auto c:a) cout << c << ' ';
    cout<<endl;
    printf("size = %d\nempty = %d", a.size(), a.empty()); //a.empty()判断是否为空,范围true或false
    printf("%d %d", a.front(), a.back());   //front()返回第一个值 back返回第二个值
}
/*输出为
1 2 3 4 
1 2
size = 2
empty = 0 
1 2          */

队列queue

queue结构数据从尾部输入,从头部弹出 priority queue弹出元素为所有数中的最大值
循环队列 queue操作:push(从队尾插入); pop(从队头弹出); front(返回队头元素); back(返回队尾元素)
优先队列 priority_queue操作:push(把元素插入堆); pop(删除堆顶元素); top(查询堆顶元素(最大值))

#include
#include
using namespace std;

int main()
{
    queue<int> p;
    p.push(1);      //在队尾插入一个元素
    p.push(2);
    p.pop();        //弹出对头的元素(1)
    cout << p.front() <<endl;      //返回对头(2)
    cout << p.back() << endl;       //返回队尾(2)

    priority_queue<int> b; //大根堆
    b.push(1);
    b.push(3);
    b.pop();  //删除最大值3
    cout << b.top() << endl; // 返回最大值1(即堆顶元素)
    b = priority_queue<int>(); //队列没有clear函数,因此可以用这种方法删除
    cout << b.size() << endl; //0

    priority_queue<int,vector<int>,greater<int>> q; //小根堆

    //若要定义结构体类型的有限队列,大根堆要重载小于号,小根堆要重载大于号
    struct Rec{
        int a, b;
        bool operator<(const Rec& t) const
        {
            return a < t.a;
        }
    };
    priority_queue<Rec> d;   //优先队列支持push,pop,top操作,但没有back,front操作
    d.push({1,2});
    d.push({2,4});
    d.push({2,3});
    cout << d.top().b; //弹出了4
}

栈stack

队尾插入,队尾弹出。支持操作push(向栈顶插入), pop(弹出栈顶元素), top(返回栈顶元素)

双端队列deque

双端队列deque是一个支持在两端高效插入或删除元素的连续线性存储空间。它就像是vector和queue的结合。与vector相比,deque在头部增删元素仅需要O(1)的时间,而vector在头部插入需要O(n),因为所有后面的元素都要移动一位;与queue相比,deque像数组一样支持随机访问。但因为常数较大,平均来看deque运行效率慢于vector和stack.
支持操作:; front/back(队头/队尾元素); push_back(在队尾加入); push_front(在队头加入); pop_back(删除队尾元素); pop_front(删除队头元素); clear(清空队列)

#include
#include
using namespace std;

int main()
{
    deque<int> a;
    a.push_back(1);  //队尾插入
    a.push_front(2); //队首插入
    for(auto c:a) cout << c << ' '; //2 1
    cout << endl << a.front() << ' '<< a.back() << endl; //2 1
    for(int i = 0; i < a.size(); i++) cout << a[i] << ' '; //支持随机访问
    cout << endl;
}

集合set

头文件set主要包括set和multiset两个容器,分别是“有序集合”和“有序多重集合”,即前者的元素不能重复,而后者可以包含若干个相等的元素。set和multiset的内部实现是一棵红黑树,它们支持的函数基本相同。
操作:

  • begin/end:返回集合首、尾迭代器,时间复杂度均为O(1),begin()是指向集合中最小元素的迭代器,end()是指向集合中最大元素的下一个位置的迭代器。
  • s.insert(x):把一个元素x插入到集合s中,时间复杂度为O(logn)。在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。
  • s.find(x):在集合s中查找等于x的元素,并返回指向该元素的迭代器若不存在,则返回s.end()。时间复杂度为O(logn)。
  • lower_bound/upper_bound:
    • s.lower_bound(x) 查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
    • s.upper_bound(x) 查找大于x的元素中最小的一个,并返回指向该元素的迭代器。
  • erase: 设it是一个迭代器,s.erase(it) 从s中删除迭代器it指向的元素,时间复杂度为O(logn)
  • count: s.count(x) 返回集合s中等于x的元素个数,时间复杂度为 O(k +logn),其中k为元素x的个数。
  • 迭代器iterator 设it是一个迭代器,例如set::iterator it;支持*解除引用,仅支持++--两个算数操作
    若把it++,则it会指向“下一个”元素。这里的“下一个”元素是指在元素从小到大排序的结果中,排在it下一名的元素。同理,若把it--,则it将会指向排在“上一个”的元素。
#include
#include
using namespace std;

int main()
{
    set<int> a;
    multiset<int> b;

    for(int i  =0; i < 10; i++) a.insert(i);
    set<int>:: iterator it = a.begin();
    if(a.find(8) == a.end()) cout << "找不到"<< endl; //判断有没有8这个元素
    else it = a.find(8);
    cout << *it << endl;


    struct Rec{
        int x, y;
        bool operator<(const Rec &t) const
        {
            return  x+y < t.x+t.y; //按照两个元素的和来排序
        }
    };

    set<Rec> c;
    c.insert({1,2});
    c.insert({0,4});
    cout<< c.begin()->x << endl;  //因为是按照x+y的大小来排序,因此第一个元素的x位为1
}

map

map容器是一个键值对key-value的映射,其内部实现是一棵以key为关键码的红黑树。Map的key和value可以是任意类型,其中key必须定义小于号运算符。
size/empty/clear/begin/end均与set类似。
Insert/erase 与set类似,insert参数是pair,erase参数可以是数对也可以是key
find map.find(x)在变量名为h的map中查找key为x的二元组。
[] 操作符是map最吸引人的地方。我们可以很方便地通过h[key]来得到key对应的value,还可以对h[key]进行赋值操作,改变key对应的value。

#include
#include
using namespace std;

int main()
{
    map<string,int> m;
    m["hello"] = 2;
    cout << m["hello"] << endl;

    map<string, vector<int>> n;
    n.insert({"a",{}});
    n.erase("a");                       //删除map中的元素
    //n.erase({"a",{}});                //也可以这种方式删除
    n["b"] = vector<int>({1,2,3,4});    //增加map中的元素
    cout << n["b"][1] << endl;  //返回2;

    map<string, vector<int>>::iterator it = n.find("b");
    cout << it->second[1] <<  endl;  //it->first返回key,it->second返回value
}

其它容器

  • unordered_set S;底层实现是哈希表,时间复杂度为O(1)比set效率高。它除了内部元素无序之外,其他所有性质与set相同,因此除了lower_bound/upper_bound函数之外(因为是无序的)其余函数都可以使用,不支持二分。
  • unordered_multiset S1;可以存储重复元素,实验原理为哈希表
  • unordered_map a相比map优点是复杂度O(1)效率更高,缺点是不支持二分。
  • bitset b定义长度为n的二进制串,可以像数组一样定义每一bit的值,还可以进行位运算
#include
#include
using namespace std;

int main()
{
    bitset<5> a,b;
    a[0] = 1;
    a[1] = 1;
    b[1] = 1;
    a &= b;                     // 按位与运算
    cout << a.count() << endl;  //返回a中1的个数
    a.set(3);                   //设置下标为3的位置为1
    cout << a <<endl;           //01010 共5位
}
  • pair
#include
using namespace std;

int main()
{
    pair<string,int> a;
    a = {"wzz",22};
    cout << a.first <<' ' << a.second <<endl;
    a = make_pair("wsx",21);
    cout << a.first <<' ' << a.second <<endl;
}
/*
wzz 22
wsx 21 */

常用库函数

reverse

#include
#include
#include
using namespace std;

int main()
{
    vector<int> n = {1,2,3,4};
    reverse(n.begin(), n.end()); //翻转vector,左右两个参数为vector开始位置和结尾位置的迭代器,左闭右开
    for(auto c:n) cout << c << ' ';
    cout << endl;

    int a[] = {1,2,3,4,5};
    reverse(a, a+5);            //对数组翻转,左右两个参数为指针
    for(auto c:a) cout << c << ' ';
    cout << endl;
}

unique——去重函数

返回去重之后的尾迭代器(或指针),仍然为前闭后开,即这个迭代器是去重之后末尾元素的下一个位置。该函数常用于离散化,利用迭代器(或指针)的减法,可计算出去重后的元素个数。

#include
#include
#include
using namespace std;

int main()
{
    int a[] = {1,1,2,2,3,4,5,5};
    int m = unique(a, a+8) - a ; //得到去重之后的个数
    cout << m << endl;
    for(int i = 0; i < m; i++) cout << a[i] << ' '; //注意:数组的5到7位仍然有元素
    cout << endl;

    vector<int> b({1,1,2,2,3,4,5,5});
    b.erase(unique(b.begin(),b.end()), b.end());//相当于将去重后将vector后面的空间擦除
    for(auto c: b) cout << c << ' ';            //1 2 3 4 5
    cout << endl;
}

random_shuffle 随机打乱

用法与reverse相同,用于生成随机数组

#include
#include
#include
#include
using namespace std;

int main()
{
    srand(time(0));
    vector<int> a({1,2,3,4,5});
    random_shuffle(a.begin(),a.end());
    for(auto c:a) cout << c << ' ';
    cout << endl;
}

sort

对两个迭代器(或指针)指定的部分进行快速排序。可以在第三个参数传入定义大小比较的函数,或者重载“小于号”运算符。

#include
#include
#include
using namespace std;

bool cmp(int a, int b){
    return a < b;       //定义排序方法,a
}

struct point{
    int x, y;
} b[5];

bool cmp2(point a, point b){  //结构体中y值小的排前面
    return a.y < b.y;
}

int main()
{
    vector<int> a({2,3,1,5,4});
    sort(a.begin(),a.end(),cmp);
    for(auto c:a) cout << c << ' ';
    cout << endl;

    sort(a.begin(),a.end(),greater<int>()); //从大到小排列
    for(auto c:a) cout << c << ' ';
    cout << endl;

    for(int i = 0; i < 5; i++){
        b[i].x = i;
        b[i].y = -i;
    }
    sort(b, b+10, cmp2);      //对结构体排序需要定义比较标准
    for(auto c:b) printf("(%d,%d) ", c.x, c.y);
}
/*
1 2 3 4 5 
5 4 3 2 1
(4,-4) (3,-3) (2,-2) (1,-1) (0,0)  */

你可能感兴趣的:(c语言,stl,c++)