C++高级编程(三)——代码实践

01 深度优先搜索迷宫路径

02 广度优先搜索迷宫路径

03 大数加减法

#include<iostream>
#include<string>
#include<algorithm>

using namespace std;

class BigInt {
public:
    BigInt(string str) : strDigit(str) {}
private:
    string strDigit;
    friend ostream& operator << (ostream &out, const BigInt &src);
    friend BigInt operator + (const BigInt &lhs, const BigInt &rhs);
    friend BigInt operator - (const BigInt &lhs, const BigInt &rhs);
};

//打印函数
ostream& operator << (ostream &out, const BigInt &src) {
    out << src.strDigit;
    return out;
}

BigInt operator+(const BigInt &lhs, const BigInt &rhs) {
    /*
    遍历字符串l, r 从后往前遍历
    同位置的数字相加, 进位flag 存入一个结果string result中
    同时完成
    某个字符串先完成都要考虑进位
    */
    string result;
    bool flag = false;
    int i = lhs.strDigit.size() - 1;
    int j = rhs.strDigit.size() - 1;

    for (; i >= 0 && j >= 0; --i, --j) {  
        int ret = lhs.strDigit[i] - '0' + rhs.strDigit[j] - '0';
        if (flag) {  // 给下一次进位+1
            ret += 1;
            flag = false;
        }

        if (ret >= 10) {
            ret %= 10;
            flag = true;
        }
        result.push_back(ret + '0');  // 最后需要把字符串反转  ret + ‘0’ 就是char的‘x’
    }

    if (i >= 0) {
        while (i >= 0) {
            int ret = lhs.strDigit[i] - '0';
            if (flag) {
                ret += 1;
                flag = false;
            }
            if (ret >= 10) {
                ret %= 10;
                flag = true;
            }
            result.push_back(ret + '0');
            i--;
        }
    }

    if (j >= 0) {
        while (j >= 0) {
            int ret = rhs.strDigit[j] - '0';
            if (flag) {
                ret += 1;
                flag = false;
            }
            if (ret >= 10) {
                ret %= 10;
                flag = true;
            }
            result.push_back(ret + '0');
            j--;
        }
    }

    reverse(result.begin(), result.end());
    return result;
}

BigInt operator- (const BigInt &lhs, const BigInt &rhs) {
    /*
    找大的字符串左减数, 小的左被减数
    遍历两个字符串,减法, 借位(bool flag)  string result 存下来
    */
   string result;
   bool flag = false;
   bool minor = false;

   string maxStr = lhs.strDigit;
   string minStr = rhs.strDigit;

   if (maxStr.length() < minStr.length()) {
       maxStr = rhs.strDigit;
       minStr = lhs.strDigit;
       minor = true;
   } else if (maxStr.length() == minStr.length()) {
       if (maxStr < minStr) {
           maxStr = rhs.strDigit;
           minStr = lhs.strDigit;
           minor = true;
       } else if (maxStr == minStr) {
           return string("0");
       }
   }
   int i = maxStr.length() - 1;
   int j = minStr.length() - 1;

   for (; i >= 0 && j >= 0; --i, --j) {
       int ret = maxStr[i] - minStr[j];
       if (flag) {
           ret -= 1;
           flag = false;
       }

       if (ret < 0) {
           ret += 10;
           flag = true;
       }
       result.push_back(ret + '0');
   }

   while (i >= 0) {
       int ret = maxStr[i] - '0';
       if (flag) {
           ret -= 1;
           flag = false;
       }

       if (ret < 0) {
           ret += 10;
           flag = true;
       }
       result.push_back(ret + '0');
       i--;
   }

   if (minor) {
       result.push_back('-');
   }

   reverse(result.begin(), result.end());
   return result;
}

int main() {
    BigInt int1("98798787987978798789797");
    BigInt int2("6151651651654164646546546546546");
    BigInt int3("564654656454654");
    BigInt int4("123");
    BigInt int5("456");

    cout << int4 + int5 << endl;

    cout << int5 - int4 << endl;

    system("pause");
    return 0;
}

04 海量数据查重

哈希表

#include<iostream>
#include<unordered_set>
#include<vector>

using namespace std;

int main() {
    vector<int> vec;
    for (int i = 0; i < 20000; i++) {
        vec.push_back(rand());
    }

    unordered_set<int> myset;
    for (int val : vec) {
        if (myset.find(val) != myset.end()) {
            cout << "第一个重复的数据为 " << val << endl;
            break;
        } else {
            myset.insert(val);
        }
    }

    system("pause");
    return 0;
}

位图法

#include<iostream>
#include<unordered_set>
#include<vector>
#include<memory>

using namespace std;

/*
有1亿个整数,最大值不超过1亿,求第一个重复的    内存限制100M
1亿 = 100M 
整数 4byte  100 * 4 = 400M   哈希表扩容  400*2 = 800M


位图法
100000000 / 32 + 1 = 3125001 = 3.125M
数据的个数与最大值相当
数字是否出现过的状态,存储到一个位图数组中

step:
1.求出最大值  char bitmap[max / 8 + 1]
2.根据 /  %  两个操作 映射到元素对应的位  
3.读取该位的值   如果为0 元素未出现过  如果为1  元素出现过
  如何获取该位的值 按位与   与上一个 该位是1 其他位是0的数   bitmap[index] & (1 << offset)
  如何把这个位置置为1  按位或 bitmap[index] | (1 << offset)  =》 赋给 bitmap[index]
*/

int main() {
    vector<int> vec{12, 78, 90, 78, 123, 8, 9, 90};

    int max = vec[0];
    for (int i = 1; i < vec.size(); i++) {
        if (vec[i] > max) {
            max = vec[i];
        }
    }

    int* bitmap = new int[max / 32 + 1]();
    unique_ptr<int> ptr(bitmap);

    for (auto key : vec) {
        int index = key / 32;
        int offset = key % 32;

        if (0 == (bitmap[index] & (1 << offset))) {
            bitmap[index] |= (1 << offset);
        } else {
            cout << key << "重复出现过!!!" << endl;
        }
    }    
    system("pause");
    return 0;
}

布隆过滤器

#include<iostream>
#include<unordered_set>
#include<vector>
#include<memory>
#include "stringhash.h"

using namespace std;
/*
布隆过滤器  位图与哈希的结合  
存在的意义    判断某个数组不存在!!!

位数组 + k个哈希函数

hash1(key) = pos0   0
hash2(key) = pos1   4
hash3(key) = pos2   6

hash1(key) = pos0   2
hash2(key) = pos1   4
hash3(key) = pos2   5
位数组对应下标 置 1

增加一个元素
1.经过k个哈希函数计算,得到bitmap位数组里面的一组位的序号
2.相应的位置为1
搜索一个元素
1.经过k个哈希函数计算,得到bitmap位数组里面的一组位的序号
2.判断上面几个位置的值如果全是1 证明相应的key存在 如果有一个是0 则证明key不在boom filter中

产生哈希冲突  不同的key经过k个哈希函数计算后共用同一个位  无法删除  删除时会把其他key的状态位失效

bloom filter查询一个key值是否存在 如果查出来key经过k个哈希函数处理后 对应的位为1  能说明这个key存在么
hash1(key) = 0
hash2(key) = 2
hash3(key) = 4
在添加前两个数时  0 2 4位均置为1  实际key不存在    =》 Bloom Filter说数据在  其实数据不一定在 存在数据误判!!!!  改变哈希函数的个数和位数组大小可以降低误判率      =》  Bloom Filter说数据不在  那么数据肯定不存在!!!!
综合哈希表查询的快  以及位图数组  省空间


举例说明:
(1) 场景一:提示过滤一些非法的网站或者是钓鱼网站
浏览器 https://www.xxx.com/
Bloom Filter: 把所有可能有问题的URL添加到布隆过滤器中
用户访问网址时  先查找是否在黑名单中  
存在  会进行提示 当前网站有风险禁止访问
不存在   肯定是白名单  合法网站

(2) 场景二:redis缓存中的应用   mysql 磁盘IO   redis 内存IO
查看key到底在不在  而且还要效率高  最好还省内存
bloom filter
setBit(key)
getBit(key)   =》   判断key不存在  =》 db mysql  =》 缓存redis  =》返回
              =》   key存在       =》 redis中找key
*/

class BloomFilter {
public:
    BloomFilter(int bitSize = 1471)
        : bitSize_(bitSize) {
            bitMap_.resize(bitSize_ / 32 + 1);
        } 

public:
    // 添加元素
    void setBit(const char* str) {
        //计算k组哈希函数的值
        int idx1 = BKDRHash(str) % bitSize_;
        int idx2 = RSHash(str) % bitSize_;
        int idx3 = APHash(str) % bitSize_;

        //把相应的idx1, idx2, idx3 这几个位置全部置为1

        int index = 0;
        int offset = 0;

        index = idx1 / 32;
        offset = idx1 % 32;
        bitMap_[index] |= (1 << offset);

        index = idx2 / 32;
        offset = idx2 % 32;
        bitMap_[index] |= (1 << offset);

        index = idx3 / 32;
        offset = idx3 % 32;
        bitMap_[index] |= (1 << offset);
    }

    // 查询元素

    bool getBit(const char* str) {
        //计算k组哈希函数的值
        int idx1 = BKDRHash(str) % bitSize_;
        int idx2 = RSHash(str) % bitSize_;
        int idx3 = APHash(str) % bitSize_;

        //把相应的idx1, idx2, idx3 这几个位置全部置为1

        int index = 0;
        int offset = 0;

        index = idx1 / 32;
        offset = idx1 % 32;
        if (0 == (bitMap_[index] & (1 << offset))) return false;        

        index = idx2 / 32;
        offset = idx2 % 32;
        if (0 == (bitMap_[index] & (1 << offset))) return false;     

        index = idx3 / 32;
        offset = idx3 % 32;
        if (0 == (bitMap_[index] & (1 << offset))) return false;     

        return true;
    }
private:
    int bitSize_;   // 位图的长度   可以存储32位
    vector<int> bitMap_;  // 位图数组
};

//黑名单

class BlackList {
public:
    void add(string url) {
        blockList_.setBit(url.c_str());
    }
    bool query(string url) {
        return blockList_.getBit(url.c_str());
    }
private:
    BloomFilter blockList_;
};

int main() {
    BlackList list;
    list.add("www.baidu.com");
    list.add("www.360buy.com");
    list.add("www.tmall.com");

    string url = "www.ali.com";
    cout << list.query(url) << endl;  
    system("pause");
    return 0;
}

05 海量数据求topK

大小根堆

#include<iostream>
#include<vector>
#include<time.h>
#include<queue>

using namespace std;

int main() {
    vector<int> vec;
    srand(time(NULL));
    for (int i = 0; i < 10; i++) {
        vec.push_back(rand() % 10);
    }

    // 求vec中值最小的前5个元素
    priority_queue<int> maxheap;
    int k = 5;

    // 由前k个元素构建一个大根堆
    for (int i = 0; i < k; i++) {
        maxheap.push(vec[i]);
    }

    for (int i = 0; i < vec.size(); i++) {
        cout << vec[i] << " ";
    }
    cout << endl;

    // 遍历剩余的元素直到最后
    for (int i = k; i < vec.size(); i++) {
        if (maxheap.top() > vec[i]) {
            maxheap.pop(); //把堆顶大元素出掉
            maxheap.push(vec[i]); // 将新元素push进去大根堆 然后自己调整
        }
    }

    while (!maxheap.empty()) {
        cout << maxheap.top() << " ";
        maxheap.pop();
    }
    cout << endl;


    system("pause");
    return 0;
}

快排分割

#include<iostream>
#include<vector>
#include<time.h>
#include<queue>
#include<functional>
#include<unordered_map>

using namespace std;

/*
快排分割求topk
*/
//快排分割函数
void SelectTopK(vector<int>& vec, int begin, int  end, int k) {
    int val = vec[begin];
    int i = begin;
    int j = end;

    // i == j的时候返回
    while (i < j) {
        while (i < j && vec[j] > val) j--;   // 找到第一个vec[j]小于val的位置
        if (i < j) {
            vec[i] = vec[j];   // 把小于val的vec[j]赋给vec[i]
            i++;               //i位置加1
        }
        
        while (i < j && vec[i] < val) i++;
        if (i < j) {
            vec[j] = vec[i];
            j--;
        }
    }
    vec[i] = val;

    if (i == k - 1) {
        return;
    } else if (i > k - 1) {
        SelectTopK(vec, begin, i - 1, k);
    } else if (i < k - 1) {
        SelectTopK(vec, i + 1, end, k);
    }
}

int main() {
    vector<int> vec = {64, 45, 52, 80, 66, 68, 0, 2, 18, 75};
    int size = vec.size();

    //求值最小的前3个元素
    int k = 3;
    SelectTopK(vec, 0, size - 1, k);

    for (int i = 0; i < k; i++) {
        cout << vec[i] << " ";
    }
    cout << endl;
    system("pause");
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-特立独行的猪-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值