考试之前 c语言速成c++笔记

速成c++

假期参加了一个考试,可以选择各种语言作答。

我怕c语言太难了,怎么说呢,比如leetcode第一题,(对我就做过第一题)。c语言版本的题解长这样。

struct hashTable {
    int key;
    int val;
    UT_hash_handle hh;
};

struct hashTable* hashtable;

struct hashTable* find(int ikey) {
    struct hashTable* tmp;
    HASH_FIND_INT(hashtable, &ikey, tmp);
    return tmp;
}

void insert(int ikey, int ival) {
    struct hashTable* it = find(ikey);
    if (it == NULL) {
        struct hashTable* tmp = malloc(sizeof(struct hashTable));
        tmp->key = ikey, tmp->val = ival;
        HASH_ADD_INT(hashtable, key, tmp);
    } else {
        it->val = ival;
    }
}

int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
    hashtable = NULL;
    for (int i = 0; i < numsSize; i++) {
        struct hashTable* it = find(target - nums[i]);
        if (it != NULL) {
            int* ret = malloc(sizeof(int) * 2);
            ret[0] = it->val, ret[1] = i;
            *returnSize = 2;
            return ret;
        }
        insert(nums[i], i);
    }
    *returnSize = 0;
    return NULL;
}

c++长这样

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hashtable;
        for (int i = 0; i < nums.size(); ++i) {
            auto it = hashtable.find(target - nums[i]);
            if (it != hashtable.end()) {
                return {it->second, i};
            }
            hashtable[nums[i]] = i;
        }
        return {};
    }
};

我知道不能给我自己算法不行找这种理由,但是这不影响我晚上考试,下午开始速成c++。

因为是速成,所以什么都没深究,能用就行,能看懂就行。比如说如果你能看懂我的速成笔记,你就能看懂上面这题解。

有些内容记得引入一下头文件,因为是速成,所以我用的万能头。

using namespace std

跟python的import差不多,写了using namespace std就可以直接用cin , cout。

std是一个命名空间,这两个函数在这个命名空间里,如果不引入命名空间,就找不到这两个函数是什么意思了。

不写也不是不能用,就是得写std::cin std::cout,相当于直接一个个写出来“cin这个函数在std命名空间里找” “cout这个函数在std命名空间里找”这样也能用。

但是using namespace std就相当于”找不到的函数都在std命名空间里找“,更方便一些。

cin cout

输入和输出。
cin连>> cout连<<

string类

string a="asdf";就跟你char a[5]="asdf"差不多。
本质上其实是不同的数据类型,string是一个类,这个类里有很多方法,比如a.length()。
定义string的时候不需要写容量5,在内存中是怎么保存的呢。
这个类里有一个属性是这个string的字符串的头指针_Ptr,
当我们向string变量赋值时,它是通过动态分配内存给_Ptr来存储字符串,分配到的内存容量存到类的另一个属性cap里。
对这个string重新赋值的时候,先检查cap能不能放下新的值,不够的话重新分内存,copy过去。

有可以reverse的方法,也有类似于strstr的方法,用的时候再百度吧。

博文

引用

引用,相当于起别名。

int a=4;
int &b=a;

这以后b和a就完全相同了,他们的内存地址一样,里面存的都是一样的4,
不是说b是个指针指向了a,而是说b就是a。
此后写a=5;或者b=5;他们都变成了5,因为他们就是一个东西。

可以试着打印一下b,a,&b,&a会发现它们都一样。

引用传递是一种不同于值传递的参数传递方式,改变形参就是改变实参。

void yinyongchuandi(int &q)
//这是引用传递,一种不同于值传递的参数传递方式。可以直接改变实参
{
    q = 2;
}
int main()
{
    int a=1;
    yinyongchuandi(a);
    //a=2
}

很适合想要返回多个值的场合。

vector

也是一个类,动态数组。采用的数据结构为线性连续空间。
一开始不用像静态数组一样一定要说好容量,且不能扩充,vector的容量可以扩充。

它的时间复杂度和静态数组一样,修改和pushback都是O(1),insert什么的是O(n)。

   class vector {...

    protected:

        iterator start;                     // 表示目前使用空间的头

        iterator finish;                   // 表示目前使用空间的尾

        iterator end_of_storage;  // 表示可用空间的尾​

     ...};

我们在使用 vector 时​,最常使用的操作恐怕就是插入操作了(push_back),那么当执行该操作时,该函数都做了哪些工作呢?

该函数首先检查是否还有备用空间,如果有就直接在备用空间上构造元素,并调整迭代器 finish,使 vector 变大。如果没有备用空间了,就扩充空间,重新配置、移动数据,释放原空间。​

迭代器是个指针,begin相当于指向a[0],end指向最后一个元素的下一个位置。

vector<int>::iterator g = f.begin();
//这就是定义了一个迭代器,和f.begin()一样
    while (g != f.end())

    {
        cout << *g << " ";
        g++;
    }

当对迭代器对应的容器进行任何添加或删除操作(不包括修改容器内元素值),则其所有与该容器相关联的迭代器就会失效,需要重新赋值。

set

    set<string> l;
    l.insert("banana");
    l.insert("peach");
    l.insert("fox");
    l.erase("fox");
//无序集合,插入这几个元素
    cout << l.count("fox") << " " << l.size() << " " << (l.find("peach") == (++l.begin())) << endl;
    //fox有0个  集合里元素有2个 find peach返回的迭代器是第二个,
//count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。
    if (l.find("fox") == l.end())
    //为什么是 == l.end()呢,首先要知道,end指向最后一个元素的后一个位置,比如数组的长度为5,有5个元素,f.end()指向的就是不存在的“第六个元素”,然后,find方法会从一个元素一个个向后寻找,看哪个等于要找的东西,等到所有的都看完了(迭代器停在“第六个元素”那里了)还没找到,find方法就会停下来
    {
        cout << "fox not found\n";
    }

map

我好困
map储存键值对,键值的类型都可以自己确定,可以直接通过键取下标。
如果存在就返回值,不存在就返回0.
遍历使用迭代器,自己会按着键排序。

能进行算术运算的迭代器只有随机访问迭代器,要求容器元素存储在连续内存空间内,即vector、string、deque的迭代器是有加减法的;而map、set、multimap、multiset、list的迭代器是没有加减法的。他们仅支持++itr、–itr这些操作(下面的代码块用了一次)。

(他们内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。)

	map<string, int> n;
    n["chicken"] = 12;
    n["dog"] = -6;
    cout << n["cat"] << " " << n["dog"] << endl;
    //光是访问n["cat"]就相当于添加了这个键,值默认为0
    if (n.find("chicken") != n.end())
    {
        cout << "chicken exists" << endl;
    }
    if (n.count("chicken") != 0)
    {
        cout << "chicken exists" << endl;
    }
    for (map<string, int>::iterator iter = n.begin();
        iter != n.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }

unordered

unordered map unordered set就是不带排序的map set
可以省时间

因为map set内部自带排序,也就是你不按顺序往里面insert一堆东西,最后你用迭代器遍历一遍一会发现是按顺序输出的。可以试试下面的代码。

#include <iostream>
#include <set>
using namespace std;

int main()
{
    set<int> st;
    set<int>::iterator it;
    st.insert(11);
    st.insert(122);
    st.insert(13);
    st.insert(1);
    for (it = st.begin(); it != st.end(); it++)
    {
        cout << *it << endl;
    }

    set<string> st1;
    set<string>::iterator it1;
    st1.insert("abc");
    st1.insert("bca");
    st1.insert("ab");
    st1.insert("a");
    for (it1 = st1.begin(); it1 != st1.end(); it1++)
    {
        cout << *it1 << endl;
    }

    return 0;
}

所以因为这个“自动排序”肯定会花一些时间,在不需要它的自动排序的场合,可以用unordered set代替set。

说到自动排序,当数据元素增多时,set的插入和搜索速度变化如何?

在set中查找是使用二分查找,所以不用担心效率。

map也一样。

stack

    stack<int> o;
    o.push(1);
    o.push(2);
    o.pop();
    cout << o.top() << " " << o.size() << " " << o.empty() << endl;

也就只能做这些了,stack只能操作栈顶,不能便利,你用一个迭代器,或者数组下标o[1] o[2]访问是不行的,只能用o.top()方法看栈顶是什么。

如果想访问所有元素,那就得用vector模拟栈,push_back, pop_back是一样的。

queue

    queue<int>p;
    for (int i = 0;i < 5;i++)
    {
        p.push(i);
    }
    p.pop();
    cout << "front:" << p.front() << " end:" << p.back() << endl;

只能访问首尾,要是用vector模拟队列,出队会很慢(弹出队首是O(n)好像)。

//升序队列
priority_queue <int,vector,greater > q;
//降序队列
priority_queue <int,vector,less >q;

优先队列放进去就自动排序了!

sort

	int q[5] = { 2,3,7,8,5 };
    sort(q, q + 5);
    //sort可以用于数组和vector,vector的参数是迭代器,如begin,end,比如
	//sort(f.begin(), f.end());
	//数组的参数是指针
    for (int i = 0;i < 5;i++)
    {
        cout << q[i] << " ";
    }cout << endl;

    int r[5] = { 2,3,7,8,5 };
    sort(r, r + 5, cmp);
    //sort可以用于数组和vector,vector的参数是迭代器,如begin,end,数组的参数是指针
    for (int i = 0;i < 5;i++)
    {
        cout << r[i] << " ";
    }cout << endl;
bool cmp(int a, int b)
{
    return a > b;//如果返回真,第一个参数在第二个参数前面
}

二分

自带,快捷啊,一行就完事了。

	int a[100]= {4,10,11,30,69,70,96,100};
    int b=binary_search(a,a+9,4);//查找成功,返回1
    cout<<"在数组中查找元素4,结果为:"<<b<<endl;
    int c=binary_search(a,a+9,40);//查找失败,返回0
    cout<<"在数组中查找元素40,结果为:"<<c<<endl;
    int d=lower_bound(a,a+9,10)-a;
    cout<<"在数组中查找第一个大于等于10的元素位置,结果为:"<<d<<endl;
    int e=lower_bound(a,a+9,101)-a;
    cout<<"在数组中查找第一个大于等于101的元素位置,结果为:"<<e<<endl;
    int f=upper_bound(a,a+9,10)-a;
    cout<<"在数组中查找第一个大于10的元素位置,结果为:"<<f<<endl;
    int g=upper_bound(a,a+9,101)-a;
    cout<<"在数组中查找第一个大于101的元素位置,结果为:"<<g<<endl;

我速成的时候敲的代码

#include <bits/stdc++.h>
using namespace std;

void yinyongchuandi(int& q)
//这是引用传递,一种不同于值传递的参数传递方式。可以直接改变实参
{
    q = 2;
}
bool cmp(int a, int b)
{
    return a > b;//如果返回真,第一个参数在第二个参数前面
}
template <typename T>//照葫芦画瓢用了模板,调用下面的函数方便
void bianli(vector<T> f)
{
    typename vector<T>::iterator g;
    g = f.begin();
    //auto g = f.begin();//自动确定数据类型 这玩意特别方便,根据右值的类型就知道左值的类型了,但是只有c11能用
    while (g != f.end())
    {
        cout << *g << " ";
        g++;
    }
    cout << endl;
}
struct Node
{
    int value;
    struct Node* next;
};
int main()
{
    string a = "world";
    // cin >> a; 这个相当于scanf%s,到空格就停,忽略前面的空白符
    // getline(cin, a); 这个相当于gets,一行有啥是啥,从缓冲区取回车并忽略,字符串里没回车
    cout << a << " " << a.length() << endl;
    string b = "hello";
    cout << a + b << endl;//自带strcat
    cout << a[2] << endl;
    cout << (a > b) << endl;//自带strcmp

    int c = 1;
    int& d = c;
    printf("%p %p\n", &c, &d);
    cout << typeid(d).name() << typeid(c).name() << endl;
    //这说明d和c地址一样,类型都是int,d并不是指针或者别的类型,就是c的别名
    yinyongchuandi(c);
    cout << "c=" << c << endl;

    Node e; // c++还有个细微的不同 不用必须加struct了
    e.value = 1;

    vector<int> f; // f(10)初始化了10个0,接下来pushback就是第十一个
    vector<int> h(3, 6);//初始化三个元素,每个都是6
    f.reserve(20); 
    //如果vector的容量不够了怎么办,首先不用担心,你一直insert编译器就会默默一直给你增加长度
    //如果你想自己定这玩意的长度,可以用reserve方法和resize方法
    //如果用resize 就是20个0了,接下来pushback就是第21个 
    //用reserve的话 相当于预约了20个空间 但是没有值
    for (int i = 0; i < 5; i++)
    {
        f.push_back(i);
        // f.pop_back();
    }
    // 0 1 2 3 4
    cout << f.size() << endl;
    f[0] = 3;
    // 3 1 2 3 4
    f.insert(f.begin() + 2, 9); //在a[2]插入了9 ->3 1 9 2 3 4
    f.erase(f.begin() + 3);     //删除a[3]->3 1 9 3 4
    bianli<int>(f);

    f.insert(f.begin(), h.begin(), h.end()); // rbegin rend ++反向迭代 我没细说 可以查查这个
    bianli<int>(f);                             // 6 6 6 3 1 9 3 4
    sort(f.begin(), f.end());                //从小到大排序,这是个algorithm库里面的方法
    bianli<int>(f);
    reverse(f.begin(), f.end()); //从大到小
    // system("pause");

    //二维数组
    vector<vector<int> > k(5, vector<int>(4)); //五行四列
    //千万千万注意,这必须↑有空格,比较旧的c++版本会把两个连着的>>当成位运算
    for (int i = 0; i < k.size(); i++)        //输出二维动态数组
    {
        for (int j = 0; j < k[i].size(); j++)
        {
            cout << k[i][j] << " ";
        }
        cout << "\n";
    }

    set<string> l;
    l.insert("banana");
    l.insert("peach");
    l.insert("fox");
    l.erase("fox");
    cout << l.count("fox") << " " << l.size() << " " << (l.find("peach") == (++l.begin())) << endl;
    //fox有0个  集合里元素有2个 find peach返回的迭代器是第二个,
    if (l.find("fox") == l.end())
    {
        cout << "fox not found\n";
    }
    vector <double> m(5);//这里是为了测试template写的对不对
    for (int i = 0; i < 5; i++)
    {
        m.push_back(i);
        // f.pop_back();
    }
    bianli<double>(m);//0 0 0 0 0 0 1 2 3 4


    map<string, int> n;
    n["chicken"] = 12;
    n["dog"] = -6;
    cout << n["cat"] << " " << n["dog"] << endl;
    //光是访问n["cat"]就相当于添加了这个键,值默认为0
    if (n.find("chicken") != n.end())
    {
        cout << "chicken exists" << endl;
    }
    if (n.count("chicken") != 0)
    {
        cout << "chicken exists" << endl;
    }
    for (map<string, int>::iterator iter = n.begin();
        iter != n.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }

    stack<int> o;
    o.push(1);
    o.push(2);
    o.pop();
    cout << o.top() << " " << o.size() << " " << o.empty() << endl;


    queue<int>p;
    for (int i = 0;i < 5;i++)
    {
        p.push(i);
    }
    p.pop();
    cout << "front:" << p.front() << " end:" << p.back() << endl;

    int q[5] = { 2,3,7,8,5 };
    sort(q, q + 5);
    //sort可以用于数组和vector,vector的参数是迭代器,如begin,end,数组的参数是指针
    for (int i = 0;i < 5;i++)
    {
        cout << q[i] << " ";
    }cout << endl;

    int r[5] = { 2,3,7,8,5 };
    sort(r, r + 5, cmp);
    //sort可以用于数组和vector,vector的参数是迭代器,如begin,end,数组的参数是指针
    for (int i = 0;i < 5;i++)
    {
        cout << r[i] << " ";
    }cout << endl;

    int A[100] = { 4,10,11,30,69,70,96,100 };
    int B = binary_search(A, A + 9, 4);//查找成功,返回1
    cout << B << endl;
    int C = binary_search(A, A + 9, 40);//查找失败,返回0
    cout << C << endl;
    int D = lower_bound(A, A + 9, 10) - A;
    cout << D << endl;
    int E = lower_bound(A, A + 9, 101) - A;
    cout << E << endl;
    int F = upper_bound(A, A + 9, 10) - A;
    cout << F << endl;
    int G = upper_bound(A, A + 9, 101) - A;
    cout << G << endl;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值