001_链表
// 001_链表.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>// // 链表的数据结构// 1. 链表是由每一个节点连接起来的.struct Node {    int        nData; // 数据域    Node*    pNext; // 指针域,用于保存下一个节点的首地址};class List {    // 记录当前链表的节点个数    int m_nCount=0;    // 用于保存链表的头节点的地址    Node* m_pHead = nullptr;public:    /*!     * 函数名 : insert     * 功  能 : 将元素nData插入到链表的第nIndex位置     * 参  数 : int nIndex 插入到的下标     * 参  数 : int nData 要插入的数据     * 返回值 :  bool     */    bool insert(int nIndex, int nData)    {        // 1. 检查插入位置是否错误.        if (nIndex <0 || nIndex>m_nCount) {            return false;        }        // 2. 在堆空间中申请内存来保存新的节点        Node* pNew = new Node;        // 2.1 将要插入到链表中的数据保存在新节点.        pNew->nData = nData;        // 3. 在链表中找到插入位置的前一个节点.        // 3.1 如果插入到的是第0个位置.那么需要将        //     新节点的首地址记录在m_pHead指针中.        if (nIndex == 0) {            pNew->pNext = m_pHead;            m_pHead = pNew;        }        else {            // 循环遍历到插入位置的前一个节点.            Node* pPre = m_pHead;            for (int i = 1; i < nIndex; ++i) {                pPre = pPre->pNext;            }            // 4. 将前一个节点的pNext字段保存到新节点的pNext字段            //      这样就可以让新节点记录下一个节点            pNew->pNext = pPre->pNext;            // 5. 将新节点的首地址保存到前一个节点的pNext字段            //    这样通过前一个节点就能找到新的节点.            pPre->pNext = pNew;        }        // 6. 增加节点个数.        ++m_nCount;    }    /*!     * 函数名 : remove     * 功  能 : 从链表中删除下标为nIndex的元素     * 参  数 : int nIndex 要删除的元素所在的下标     * 返回值 :  void     */    void remove(int nIndex)    {        // 1. 判断下标是否正确        if (nIndex < 0 || nIndex >= m_nCount) {            return;        }        // 2. 找到要删除的元素的前一个节点        // 2.1 如果删除的是第0个节点. 这个节点的首地址        //     是保存在m_pHead头节点指针中.        //     因此, 直接操作头节点指针.        if (nIndex == 0) {            // m_pHead->pNext记录的是被删除节点的下一个            // 节点的首地址            // 现在将下一个节点作为新的头节点:将节点的地址            // 记录在头节点指针中.            Node* temp = m_pHead;            m_pHead = m_pHead->pNext;            delete temp;        }        else {            Node* pPreNode = m_pHead;            for (int i = 1; i < nIndex; ++i) {                pPreNode = pPreNode->pNext;            }            // 3. 通过前一个节点的pNext字段找到被删除节点            //      的首地址            Node* pRemoveNode = pPreNode->pNext;            // 4. 再通过被删除节点的pNext字段,得到被删除            //    节点的下一个节点的首地址            Node* pNextNode = pRemoveNode->pNext;            // 5. 将被删除节点的下一个节点的首地址保存到            //    被删除节点的前一个节点的pNext字段.            pPreNode->pNext = pNextNode;            // 6. 释放掉被删除节点的内存空间            delete pRemoveNode;        }        // 7. 递减当前节点个数        --m_nCount;    }    /*!     * 函数名 : find     * 功  能 : 在链表中查找元素     * 参  数 : int nData 被查找的元素     * 返回值 : int 元素在链表中的下标,找不到了就返回-1     */    int find(int nData) {        Node* pNode = m_pHead;        int nIndex = 0;        while (pNode != nullptr) {            // 判断当前遍历到的节点保存的数据            // 是否是要查找的数据            if (pNode->nData == nData) {                // 如果是,就返回下标                return nIndex;            }            // 递增下标,用于记录,当前遍历到了第几个元素            ++nIndex;            // 找到下一个节点            pNode = pNode->pNext;        }        return -1;    }    /*!     * 函数名 : at     * 功  能 : 获取指定下标的元素的数据域的引用.     * 参  数 : int nIndex 元素所在的下标     * 返回值 :  int& 返回数据的引用.这样就可以在函数外部修改节点的数据了     */    int& at(int nIndex) {        if (nIndex < 0 || nIndex >= m_nCount) {            throw std::exception("下标越界");        }        // 遍历到指定下标处的节点        Node* pNode = m_pHead;        for (int i = 0; i < nIndex; ++i) {            pNode = pNode->pNext;        }        // 返回节点的引用(返回值是int&引用类型)        return pNode->nData;    }    /*!     * 函数名 : push_back     * 功  能 : 将数据插入到链表最后一个位置     * 参  数 : int nData     * 返回值 :  void     */    void push_back(int nData) {        insert(m_nCount, nData);    }    /*!     * 函数名 : pop_back     * 功  能 : 将最后一个元素的值输出到*pData,然后删除     * 参  数 : int * pData     * 返回值 :  void     */    void pop_back(int* pData) {        if (m_nCount) {            // 先获取最后一个元素的值,并保存到            // 指针指向的内存中            *pData = at(m_nCount - 1);            // 删除该元素            remove(m_nCount - 1);        }    }    /*!     * 函数名 : push_front     * 功  能 : 将数据插入到链表的最前面     * 参  数 : int nData     * 返回值 :  void     */    void push_front(int nData) {        insert(0, nData);    }    /*!     * 函数名 : pop_front     * 功  能 : 删除链表最前面的数据, 删除前,将值输出到*pData     * 参  数 : int * pData     * 返回值 :  void     */    void pop_front(int * pData) {        if (m_nCount) {            // 先获取最后一个元素的值,并保存到            // 指针指向的内存中            *pData = at( 0 );            // 删除该元素            remove( 0 );        }    }    /*!     * 函数名 : print     * 功  能 : 打印链表中的所有元素     * 返回值 :  void     */    void print() {        Node* pNode = m_pHead;        printf("[");        while (pNode != nullptr) {            // 打印节点的数据域            printf("%d,", pNode->nData);            // 找到下一个节点            pNode = pNode->pNext;        }        printf("\b]\n");    }};int main(){    List l;    printf("测试插入功能:\n");    l.insert(0, 10);    l.insert(0, 9);    l.insert(2, 12);    l.insert(1, 11);    l.print();    // 修改链表的下标为2的项    printf("\n测试修改功能:\n");    int& rEle = l.at(2);    printf("下标为2项的值:%d\n", rEle);    rEle = 100;    printf("下标为2项的值:%d\n", rEle);    printf("\n测试查找功能:\n");    int nIndex = l.find(12);    printf("元素12在链表中的第%d项\n", nIndex);    printf("\n测试删除功能:\n");    // 删除元素9    // 1. 先通过find查找到元素9的下标    // 2. 在通过删除函数删除指定下标的元素    l.remove(l.find(9));    l.remove(3);// 9- 11 - 10 -12    l.print();    l.remove(1);    l.print();    l.remove(0);    l.print();    // 模拟栈的操作:    printf("\n模拟栈操作:\n");    int nData = 0;    l.push_back(10);    l.push_back(9);    l.push_back(8);    l.push_back(7);    l.print();    l.pop_back(&nData);    l.print();    l.pop_back(&nData);    l.print();    l.pop_back(&nData);    l.print();    l.pop_back(&nData);    l.print();    // 模拟队列的操作    printf("\n模拟队列操作:\n");    l.push_back(100);    l.push_back(101);    l.push_back(102);    l.push_back(103);    l.pop_front(&nData);    l.print();    l.pop_front(&nData);    l.print();    l.pop_front(&nData);    l.print();    l.pop_front(&nData);    l.print();}
二分法
// 二分法.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>int bin_seach(int* pArr, int nCount, int nData){    //1. 先确定开始下标和结束的下标    int nBeg = 0;    int nEnd = nCount - 1;    int nMid = (nEnd - nBeg) / 2;    int i = 1;    while (1)    {        // 判断中间位置保存的数据是否就是        // 要查找的元素        if (pArr[nMid] == nData) {            return nMid;        }        if (nBeg == nEnd) {            return -1;        }        // 开始确定下一次的查找范围        if (nData < pArr[nMid]) {            // 1. 保存开始下标不变            // 2. 将当前中间下标设置为新的结束下标            nEnd = nMid;        }        else {            // 1. 保存结束的下标不变            // 2. 将当前中间下标设置为新的开始下标            nBeg = nMid;        }        // 重新计算新的中间下标        nMid = ((nEnd - nBeg) / 2) + nBeg;        printf("循环了%d次\n", i++);    }}void sort(int *pArr, int nCount) {    for (int i = 0; i < nCount - 1; ++i) {        for (int j = 0; j < nCount - i - 1; ++j) {            if (pArr[j] > pArr[j + 1]) {                int temp = pArr[j];                pArr[j] = pArr[j + 1];                pArr[j + 1] = temp;            }        }    }}void printArr(int *pArr, int nCount) {    for (int i = 0; i < nCount; ++i) {        printf("%d,", pArr[i]);    }    printf("\b\n");}int main(){    int nArr[] = { 10,5,6,8,9,45,65,32,45 };    printArr(nArr, _countof(nArr));    sort(nArr, _countof(nArr));    printArr(nArr, _countof(nArr));    int nIndex = bin_seach(nArr, _countof(nArr), 45);    printf("45在%d\n", nIndex);}