001_容器的基本使用_vector
// 001_容器的基本使用_vector.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>using namespace std;int main(){    // vecNum是一个类对象    vector<int> vecNum;    // 增    // 将一个元素存入到动态数组中. 此时数组的元素个数等于1    vecNum.push_back(100);    // 插入的时候, 只能传递一个迭代器    // 要插入到哪个位置就需要先得到该位置的迭代器    // 迭代器就类似于一个指针    // 1. 定义迭代器    // 1.1 iterator是一个类名, 这个类定义在了vector类中.    //     iterator是一个类中类    // 1.2 vector<int>::iterator是说明iterator是在vector<int>类中的    //       vector<int>::就相当于选择指定作用域    vector<int>::iterator itr = vecNum.begin(); // 得到动态数组的第1个元素的迭代器对象    // 2. 迭代器的三种用法:    // 2.1 自增运算符: ++itr或者itr++,    //       作用: 找到容器中的下一个元素    // 2.2 自减运算符: --itr或者itr--,    //       作用: 找到容器中的上一个元素    // 2.3 取内容运算符: *itr    //        作用: 获取迭代器对应的元素的内容    cout << "itr=" << *itr << endl;// 输出了100,因为100就是第一个元素,itr刚好指向了第一个元素    // 2.3 如果容器的元素个数发生了变化(增加/删除),迭代器对象有可能    //     就失效了 , 因此,最后重新获取一个迭代器.    vecNum.insert(itr, 200);    // 删    // erase只能接收一个迭代器. 删除哪个,就需要传递哪个    // 元素对应的迭代器    // vecNum.begin() + 1 : 指的是第二个元素    vecNum.erase(vecNum.begin() + 1);    vecNum.push_back(300);    vecNum.push_back(400);    // 改(访问)    cout << "当前元素个数:" << vecNum.size() << endl;    cout << "第1个元素的值是: " << vecNum[0]<<endl;    itr = vecNum.begin();    cout << "第2个元素的值是: " << *(itr + 1) << endl;    vecNum[0] = 10000;// 通过[]运算符来修改    cout << "第1个元素的值是: " << vecNum[0] << endl;    itr = vecNum.begin();    *(itr + 1) = 20000; // 通过迭代器来修改    cout << "第2个元素的值是: " << *(itr + 1) << endl;    // 查(遍历)    // 下标遍历法    for (int i = 0; i < vecNum.size(); ++i) {        cout << vecNum[i]<<',';    }    cout << endl;    // 迭代器遍历法(通用)    // auto : 自动根据begin函数返回值类型来推测    //        出itr的变量类型,此处推测出来的是:vector<int>::iterator    for (auto itr = vecNum.begin();         itr != vecNum.end();/*循环结束条件*/         ++itr)    {        // 通过迭代器来取得元素的值        cout << *itr << ',';    }    cout << endl;    // c++的新式循环    // 格式: for( 元素类型 变量名 : 可迭代对象){}    // 元素类型 : 就是从可迭代对象中取出的元素的类型    // 变量名       : 随便起    // 可迭代对象: 所有的容器, 可以是一个数组.    // auto& d : vecNum    // auto 自动类型, 能够自动推测出从vecNum中取出的元素的数据类型是什么    // &  : 表示引用类型, 表示从vecNum中取出的元素将会被赋值给变量d    //        如果使用引用, 那么d就没有内存,直接引用vecNum中的元素, 修改    //        了d也就等于修改了保存在vecNum中的元素,顺便还能提升循环的效率    //        (没有引用的话,从vecNum获取一个元素时,就需要拷贝一次0    // 循环会自动遍历完可迭代对象的所有元素,然后自动退出.    for (auto& d : vecNum) {        cout << d << ',';    }}
002_容器的使用_list
// 002_容器的使用_list.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <list>using namespace std;int main(){    list<int> listNum;    // 增    listNum.push_back(100);    listNum.push_back(300);    listNum.insert(listNum.begin(), 200);    // **注意** : list迭代器只能使用++,或--, 不能使用+运算符    // 删    // 只能用迭代器, 但如果要删除第2个元素    list<int>::iterator itr = listNum.begin();    // itr = itr + 3;list迭代器只能使用++,或--, 不能使用+运算符    ++++itr; // 自增2次指向第2个元素    // 所有容器的erase都会删除迭代器指向的元素    // 然后删除之后itr指向就无效了, 因此就变成了一个无效迭代器    // erase会通过返回值返回一个有效的迭代器(一般是删除位置的下一个元素的迭代器)    itr = listNum.erase(itr);    // 改    // 只能通过迭代器去修改    // 例如:修改第1个元素    itr = listNum.begin();    cout << "第1个元素: " << *itr << endl;    *itr = 111111;    cout << "第1个元素: " << *itr << endl;    // 例如:修改第2个元素    ++itr; // 自增找到第二个元素    cout << "第2个元素: " << *itr << endl;    *itr = 111111;    cout << "第2个元素: " << *itr << endl;    // 查    // 通过迭代器来遍历    for (auto i = listNum.begin(); i != listNum.end(); ++i) {        cout << *i << ',';    }    cout << endl;    // 通过新式循环来遍历    for (auto& d : listNum) {        cout << d << ',';    }    cout << endl;}
003_容器的基本使用_map
// 003_容器的基本使用_map.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <map>#include <string>#include <set>using namespace std;int main(){    // 什么是键值对?    // 键 : 相当于一个索引.相当于目录中的一下.    // 值 : 就是一堆真正要保存的数据. 键相当于值的摘要.用于代表这个值.    // 例如 , 姓名:小明. 姓名:小红, 其中姓名就是键,小明就是值    //         年龄: 18 , 年龄就是键,18就是值.    //         4544545 : 小名    //        4544545就是键,小名值.    // 总是用键来索引值.    // <string, string>     // 第一个string指的是键的类型    // 第二个string指的是值的类型    // 当需要将数据保存到map容器中时,    //   保存的数据的键值对必须都是string类型.    map<string, string> m1;    map<int, string> m2;    // 增    // pair是一个键值对类    // map就是用于保存键值对类的平衡二叉树.    // map是一个平衡二叉树(红黑树)    // 树中节点的数据类型是 std::pair<typename,typename>    // 插入数据到map中的时候, 必须先给出键值对来初始化一个pair对象    // 然后再pair对象插入到map中.    pair<string,string> p1("姓名","小明");    m1.insert(p1);    //p1是一个键值对对象    cout<<"p1.first="<< p1.first<<endl; // 键值对中的键    cout << "p1.second=" << p1.second << endl;// 键值对中的值    // 也可以直接在实参中调用pair的构造函数来构造一个pair对象    m1.insert(pair<string, string>("年龄", "18"));    // 第三种方法,直接使用`[]`运算符来插入    // 实际上[]运算符会在二叉树中以"性别"作为键来搜索pair对象    // 如果没有搜索到, 函数会自动在树中插入一个用"性别"作为键    // 的pair对象, 然后再将新pair对象值赋值成"男"    m1["性别"] = "男";    // m1["姓名"]运算符会在树中以"姓名"作为键找到对应的pair    // 对象, 然后将pair对象的值返回.    string str = m1["姓名"]; // str被赋值成"小明"    str = m1["aaa"]; // 如果获取一个不存在的键的时候,就会插入一个,值有可能会随机(取决于值的类型有无构造函数)    // 删    // 直接传入一个键就行了. 对应的键值对就会被删除.    m1.erase("姓名");    // 改    cout << "性别:" << m1["性别"] << endl;    m1["性别"] = "女";    cout << "性别:" << m1["性别"] << endl;    // 查    // map保存的节点是pair对象    // 所以map的迭代器指向的元素都是pair对象.    //     cout << "遍历map\n";    for (auto itr = m1.begin();         itr != m1.end();         ++itr)    {        itr->first; //(*itr).first        cout << itr->first << "="            <<itr->second << endl;    }    m2.insert(pair<int, string>(1, "123456"));    m2.insert(pair<int, string>(2, "456789"));    m2[100] = "1111";    cout << "遍历map\n";    for (auto itr = m2.begin();         itr != m2.end();         ++itr)    {        itr->first; //(*itr).first        cout << itr->first << "="            << itr->second << endl;    }}
A星算法
A星算法.zip
平衡二叉树
// 二叉树.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <stdio.h>// 二叉查找树class AVLTree {public:    struct Node {        int nData;        // 节点的数据域        Node* pLeft;    // 左子树指针        Node* pRight;    // 右子树指针        Node() :pLeft(), pRight() {}        Node(int nData)            :nData(nData), pLeft(), pRight()        {}    };public:    int m_nCount = 0; // 树中节点个数    Node* m_pRoot = 0;// 根节点指针:记录树中的根节点地址.protected:    // 参数1是指针的引用, 为的是能够在    // 函数内部修改函数外部的实参(可以参考交换两个变量的函数)    /*!     * 函数名 : insert     * 功  能 : 将数据nData插入到pTree作为根节点的树居中     * 参  数 : Node * & pTree 树的根节点.     * 参  数 : int nData 插入的数据     * 返回值 :  void     */    bool insert(Node*& pTree, int nData) {        // 1. 判断树的根节点是否为NULL,如果为NULL        //    直接插入到根节点        bool isInsert = false;        if (pTree == nullptr) {            pTree = new Node(nData);            // 递增节点个数            ++m_nCount;            return true;        }        // 2. 如果不为空,则判断插入的数据和根节点        //    所保存的数据的大小关系        if (nData < pTree->nData) {            // 3. 如果插入数据小于根节点数据,那么就将            //    根节点的左子树作为新的根节点,让后将            //    数据插入到左子树中.            isInsert = insert(pTree->pLeft, nData);        }        else {            // 否则就插入到右子树中.            isInsert = insert(pTree->pRight, nData);        }        if (isInsert) {            sort(pTree);        }        return isInsert;    }    Node*& find(Node*& pTree, int nData) {        if (pTree == nullptr) {            return pTree;        }        // 1. 判断当前节点保存的数据是否        //    就是要查找的数据        if (pTree->nData == nData) {            // 如果是, 就返回节点本身            return pTree;        }        // 如果不是, 则判断这个数据是在节点的左子树中        // 还是在右子树中.        // 因为二叉树是左小右大的.        // 因此, 比较要删除的数据和当前节点的大小关系        // 就能知道是在左子树还是在右子树中        else if (nData < pTree->nData) {            return find(pTree->pLeft, nData);        }        else {            return find(pTree->pRight, nData);        }    }    bool remove(Node*& pTree, int nData) {        if (pTree == nullptr) {            return false;        }        bool isRemove = false;        printf("-------- 删除:%d-----  \n", nData);        printTree();        // 1. 在树中查找到要删除的节点.        Node*& pFindNode = find(pTree, nData);        // 是否能够找到节点.        if (pFindNode == nullptr) {            return false;        }        // 2. 找到节点的就是被删除的节点        //    删除时要判断节点是否是一个叶子节点        //    如果是叶子节点可以直接删除        if (pFindNode->pLeft == nullptr && pFindNode->pRight == nullptr) {            // 直接删除            delete pFindNode;            // 将指针设置为空,由于pFindNode是一个指针            // 的引用, 因此它修改的是哪里????(实际上修改的是            // 父节点的右子树指针或左子树指针)            pFindNode = nullptr;            // 递减节点个数            --m_nCount;            return true;        }        // 3. 如果不是叶子节点. 就需要在被删除节点的        //    子树中找到一个叶子节点, 然后两者的值        //    互换, 再删除掉叶子节点        // 3.1 再找叶子节点的时候, 需要考虑子树高度差        //    因此会在树高比较高的子树中找叶子节点.        int nLeftHeight = getHeight(pFindNode->pLeft);        int nRightHeight = getHeight(pFindNode->pRight);        // 3.2 树中左小右大的关系, 因此, 需要左子树中        //     找最大值, 在右子树中找最小值.            if (nLeftHeight >= nRightHeight) {            // 左子树比较高,需要找最大值            Node*& pNode = getMax(pFindNode->pLeft);            // 将当前被找到的节点和叶子节点的数据域            // 进行调换            int t = pFindNode->nData;            pFindNode->nData = pNode->nData;            pNode->nData = t;            // 删除叶子节点            // 递归删除.            isRemove = remove(pFindNode->pLeft, pNode->nData);        }        else {            // 右子树比较高,需要找最小值            Node*& pNode = getMin(pFindNode->pRight);            int t = pFindNode->nData;            pFindNode->nData = pNode->nData;            pNode->nData = t;            // 删除叶子节点            // 递归删除.            isRemove = remove(pFindNode->pRight, pNode->nData);        }        // 如果删除成功,就检测树是否平衡        if (isRemove) {            sort(pTree);        }        return isRemove;    }    /*!     * 函数名 : getHeight     * 功  能 : 求一个树的高度     * 参  数 : Node * pTree     * 返回值 :  int     */    int getHeight(Node* pTree) {        if (pTree == nullptr) {            return 0;        }        // 求出左子树的高度        int nLeftHeight =            getHeight(pTree->pLeft);        // 求出右子树的高度        int nRightHeight =            getHeight(pTree->pRight);        // 取左右子树高度的最大值作为子树的高度        int nHeight = nLeftHeight > nRightHeight ? nLeftHeight : nRightHeight;        // 本节点的高度 = 自身高度 + 子树的高度        return 1 + nHeight;    }    Node*& getMin(Node*& pTree) {        if (pTree == nullptr) {            return pTree;        }        // 二叉树是左小右大的.        // 一个树的最小值就在树的最左边        if (pTree->pLeft == nullptr) {            // 如果本节点的左子节点已经为空了            // 说明了本节点就是树中最左边的节点            // 就返回节点自身.            return pTree;        }        return getMin(pTree->pLeft);    }    Node*& getMax(Node*& pTree) {        if (pTree == nullptr) {            return pTree;        }        // 二叉树是左小右大的.        // 一个树的最大值就在树的最右边        if (pTree->pRight == nullptr) {            // 如果本节点的右子节点已经为空了            // 说明了本节点就是树中最右边的节点            // 就返回节点自身.            return pTree;        }        return getMax(pTree->pRight);    }    // 清空整颗树(后序遍历    void clear(Node*& pTree) {        clear(pTree->pLeft);        clear(pTree->pRight);        delete pTree;    }    // 前序方式遍历树    void printTreeByPreOrder(Node*& pTree) {        if (pTree == nullptr) {            return;        }        printf("%d,", pTree->nData);        printTreeByPreOrder(pTree->pLeft);        printTreeByPreOrder(pTree->pRight);    }    // 中序方式遍历树    void printTreeByInOrder(Node*& pTree) {        if (pTree == nullptr) {            return;        }        printTreeByInOrder(pTree->pLeft);        printf("%d,", pTree->nData);        printTreeByInOrder(pTree->pRight);    }    // 后序方式遍历树    void printTreeByPostOrder(Node*& pTree) {        if (pTree == nullptr) {            return;        }        printTreeByPostOrder(pTree->pLeft);        printTreeByPostOrder(pTree->pRight);        printf("%d,", pTree->nData);    }    void printTree(Node*& pTree, int nWidth, char ch) {        if (pTree == nullptr) {            return;        }        printTree(pTree->pLeft, nWidth + 2, '/');        printf("%*c%d\n", nWidth, ch, pTree->nData);        printTree(pTree->pRight, nWidth + 2, '\\');    }    /*!     * 函数名 : sortLeft     * 功  能 : 将一颗右单斜的树进行左旋,然后使其平衡     * 参  数 : Node * & pTree     * 返回值 :  void     */    void sortLeft(Node*& K) {        /*        *  K(7)        *    \                M(9)        *    M(9)             (    \        *   /   \          K(7)      N(10)        * L(8)   N(10)        )        *                    L(8)        *        * K->pRight = L        * M->pLeft = K        * K = M        */        Node* M = K->pRight;        Node*L = M->pLeft;        Node* N = M->pRight;        K->pRight = L;        M->pLeft = K;        K = M;    }    /*!     * 函数名 : sortRight     * 功  能 : 将一颗左单斜的树进行左旋,然后使其平衡     * 返回值 :  void     */    void sortRight(Node*& K) {        /*        *      K(6)                M(4)        *      /                /  )        *     M(4)             N(2)  K(6)        *    /   \                   (        *  N(2)  R(5)              R(5)        *        * K->pLeft = R        * M->pRight = K        * K = M         */        Node* M = K->pLeft;        Node* N = M->pLeft;        Node* R = M->pRight;        K->pLeft = R;        M->pRight = K;        K = M;    }    /*!     * 函数名 : sortLeftRight     * 功  能 : 先左旋再右旋,将右歪斜树变成平衡树     * 参  数 : Node * &     * 返回值 :  void     */    void sortRightLeft(Node*& K ) {        /*        *    K(6)     K(6)            N(7)        *    \           \              /      \        *      M(8)      N(7)      K(6)  M(8)        *      /            \        *    N(7)        M(8)        *       /        *   ??        * 1. 以M作为顶点. 将M形成树视为左单斜树,使用右单旋使其平衡        * 2. 以K作为顶点, 将K形成的是右单斜树, 使用左单旋使其平衡        */        sortRight(K->pRight);        sortLeft(K);    }    void sortLeftRight(Node*& K) {        sortLeft(K->pLeft);        sortRight(K);    }    void sort(Node*& pTree) {        // 1. 判断树的形状:        int nLeftHeight = getHeight(pTree->pLeft);        int nRightHeight = getHeight(pTree->pRight);        if (nLeftHeight - nRightHeight > 1) {            // 1.1 左斜            nLeftHeight = getHeight(pTree->pLeft->pLeft);            nRightHeight = getHeight(pTree->pLeft->pRight);            if (nLeftHeight > nRightHeight) {                // 1.1.1 左单斜                sortRight(pTree);            }            else {                // 1.1.2 左歪斜                sortLeftRight(pTree);            }        }        else if (nLeftHeight - nRightHeight < -1) {            // 1.2 右斜            nLeftHeight = getHeight(pTree->pRight->pLeft);            nRightHeight = getHeight(pTree->pRight->pRight);            if (nRightHeight > nLeftHeight) {                // 1.2.1 右单斜                sortLeft(pTree);            }            else {                // 1.2.2 右歪斜                sortRightLeft(pTree);            }        }    }public:    void insert(int nData) {        insert(m_pRoot, nData);    }    void remove(int nData) {        remove(m_pRoot, nData);    }    void printTree() {        printTree(m_pRoot, 2, '*');        printf("\n");    }};struct MyStruct {    int nNum = 0;    const char* pStr;};const char*& fun(const char*& p) {    return p;}int main() {    MyStruct stc = { 0, "hello" };    const char*& p = fun(stc.pStr);    p = "呵呵";    AVLTree tree;//     tree.insert(10);//     tree.insert(5);//     tree.insert(20);//     tree.insert(7);//     tree.insert(6);//     tree.printTree();// // //     tree.remove(10);//     tree.printTree();    // 测试平衡性    for (int i = 0; i<10;++i)    {        tree.insert(i);        tree.printTree( );    }    printf("删除\n");    for (int i = 0; i < 10; ++i) {        tree.remove(i);        printf("删除并旋转之后:\n");        tree.printTree();    }}