diff --git a/.github/workflows/CD.yaml b/.github/workflows/CD.yaml index 5b66325..73c2891 100644 --- a/.github/workflows/CD.yaml +++ b/.github/workflows/CD.yaml @@ -8,7 +8,6 @@ name: CD on: push: branches: - - master - next workflow_dispatch: @@ -23,6 +22,7 @@ jobs: deploy-github: name: "部署到Github-Pages" runs-on: ubuntu-latest + if: github.repository == '142vip/408CSFamily' steps: - name: Checkout Code @@ -32,28 +32,31 @@ jobs: # “最近更新时间” 等 git 日志相关信息,需要拉取全部提交记录 fetch-depth: 0 - # ## 依赖下载完成后,或执行思维导图编译 - # - name: PNPM Install - # uses: pnpm/action-setup@v2 - # with: - # version: 7 - # run_install: | - # args: [--frozen-lockfile, --registry=https://registry.npmmirror.com] + ## 安装PNPM + - name: PNPM Install + uses: pnpm/action-setup@v2 + with: + version: 8 - # 安装Node环境 + ## 安装Node环境 - name: Install Node.js uses: actions/setup-node@v3 with: node-version: 18.18.0 ## 淘宝镜像加速 registry-url: 'https://registry.npmmirror.com' + ## 缓存 + cache: 'pnpm' + ## 下载依赖,并执行初始化脚本:钩子函数、思维导图构建 - name: Install Dependencies - run: ./scripts/ci + run: | + ./scripts/ci # 运行构建脚本 - name: Build VuePress Site - run: ls -a && ./scripts/bundle build_proxy + run: | + ./scripts/bundle build_proxy - name: Deploy To GitHub Page uses: crazy-max/ghaction-github-pages@v3 @@ -68,6 +71,7 @@ jobs: name: "部署到Vercel平台" runs-on: ubuntu-latest if: github.repository == '142vip/408CSFamily' + steps: - name: Checkout Code uses: actions/checkout@v4 @@ -139,4 +143,38 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: ./408CSFamily.zip asset_name: 408CSFamily.zip - asset_content_type: application/zip \ No newline at end of file + asset_content_type: application/zip + + +# Deploy-ESC: +# name: "部署到ESC服务器" +# needs: install-init +# runs-on: ubuntu-latest +# ## 主库master、next且执行release更新时执行 +# if: github.repository == '142vip/408CSFamily' && startsWith(github.event.head_commit.message, 'chore(release):') +# +# steps: +# - name: Checkout repository +# uses: actions/checkout@v4 +# +# - name: Get Current Version +# id: version +# uses: ashley-taylor/read-json-property-action@v1.0 +# with: +# path: ./package.json +# property: version +# +# # 拉取镜像,更新服务 +# - name: Pull Image And Update ESC +# uses: appleboy/ssh-action@master +# with: +# host: ${{ secrets.SERVER_HOST }} +# port: ${{ secrets.SERVER_PORT }} +# username: ${{ secrets.SERVER_USERNAME }} +# password: ${{ secrets.SERVER_PASSWORD }} +# script: | +# docker images +# echo "-----------正在运行的服务--------" +# docker ps +# cd /service_env/ && git reset --hard && git pull origin main +# bash ./scripts/book_doc.deploy.sh jsc ${{steps.version.outputs.value}} \ No newline at end of file diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 08768b2..beba41e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -9,8 +9,8 @@ on: - next push: branches: - - master - next + # 手动触发部署 workflow_dispatch: @@ -25,9 +25,11 @@ env: jobs: - install-init: - name: "依赖安装初始化" + Base-Build: + name: "基础编译构建" runs-on: ubuntu-latest + ## 主库且拉取PR时触发 + if: github.repository == '142vip/408CSFamily' && github.event_name == 'pull_request' permissions: actions: read pull-requests: read @@ -40,58 +42,31 @@ jobs: # “最近更新时间” 等 git 日志相关信息,需要拉取全部提交记录 fetch-depth: 0 - # ## 依赖下载完成后,或执行思维导图编译 - # - name: PNPM Install - # uses: pnpm/action-setup@v2 - # with: - # version: 7 - # run_install: | - # args: [--frozen-lockfile, --registry=https://registry.npmmirror.com] - # 安装Node环境 + ## 安装PNPM + - name: PNPM Install + uses: pnpm/action-setup@v2 + with: + version: 8 + + ## 安装Node环境 - name: Install Node.js uses: actions/setup-node@v3 with: node-version: 18.18.0 ## 淘宝镜像加速 registry-url: 'https://registry.npmmirror.com' + ## 缓存 + cache: 'pnpm' + ## 下载依赖,并执行初始化脚本:钩子函数、思维导图构建 - name: Install Dependencies - run: ./scripts/ci - - - name: Cache Dependencies - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/pnpm-lock.yaml') }} - - Base-Build: - name: "基础编译构建" - runs-on: ubuntu-latest - needs: - - install-init - steps: - - name: Checkout Code - uses: actions/checkout@v4 - with: - persist-credentials: false - # “最近更新时间” 等 git 日志相关信息,需要拉取全部提交记录 - fetch-depth: 0 - - - name: Restore Dependencies From Cache - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/pnpm-lock.yaml') }} + run: | + ./scripts/ci - name: Code LintFix run: | ./scripts/lint --fix - ## 支持思维导图转化 - - name: Build Mark-Map - run: | - ./scripts/mark-map - - name: Build Site run: | ./scripts/bundle build @@ -104,7 +79,7 @@ jobs: name: "构建Docker镜像" runs-on: ubuntu-latest ## 主库且tag更新时执行 - if: github.repository == '142vip/408CSFamily' && startsWith(github.ref, 'refs/tags/v') + if: github.repository == '142vip/408CSFamily' && startsWith(github.event.head_commit.message, 'chore(release):') permissions: actions: read pull-requests: read diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..816c250 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,36 @@ +name: CodeQL + +on: + # push: + pull_request: + branches: + - next + schedule: + - cron: "30 7 * * 3" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + queries: +security-extended + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + languages: javascript + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 \ No newline at end of file diff --git a/docs/.vuepress/public/mark-map/cn-map.html b/docs/.vuepress/public/mark-map/cn-map.html index d73bb1e..bb7a773 100644 --- a/docs/.vuepress/public/mark-map/cn-map.html +++ b/docs/.vuepress/public/mark-map/cn-map.html @@ -16,11 +16,11 @@ height: 100vh; } - +
- + })(() => window.markmap,null,{"type":"heading","depth":0,"payload":{"lines":[0,1]},"content":"数据结构","children":[{"type":"heading","depth":1,"payload":{"lines":[4,5]},"content":"基础入门","children":[{"type":"heading","depth":2,"payload":{"lines":[6,7]},"content":"基本概念","children":[{"type":"list_item","depth":3,"payload":{"lines":[8,9]},"content":"数据","children":[{"type":"list_item","depth":4,"payload":{"lines":[10,11]},"content":"信息的载体","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[11,12]},"content":"客观事物属性的数、字符以及所有能够输入到计算机包中并且被计算机程序识别和处理的集合","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[13,14]},"content":"数据元素","children":[{"type":"list_item","depth":4,"payload":{"lines":[15,16]},"content":"数据的基本单位","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[16,17]},"content":"一个数据元素由若干个数据项组成","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[17,18]},"content":"数据项是构成数组元素的最小单位,且不可分割","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[19,20]},"content":"数据对象","children":[{"type":"list_item","depth":4,"payload":{"lines":[21,22]},"content":"具有相同性质的数据元素的集合","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[22,23]},"content":"数据的子集","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[24,25]},"content":"数据类型","children":[{"type":"list_item","depth":4,"payload":{"lines":[26,27]},"content":"原子类型:不可再分的数据类型","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[27,28]},"content":"结构类型:可以分解成若干分量(成分)的数据类型","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[28,29]},"content":"抽象数据类型:抽象出具组织和其相关的操作","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[30,31]},"content":"抽象数据类型(ADT)","children":[{"type":"list_item","depth":4,"payload":{"lines":[32,33]},"content":"定义:一个数学模型以及定义在该模型上的一组操作","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[33,34]},"content":"特点:与计算机内部如何表示和实现是没有关系","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[34,35]},"content":"作用:数据封装和信息隐藏,让实现与使用相分离","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[35,36]},"content":"注意:不论内部结构如何变化,只要其数学特性不变,就不会影响到外部的使用","children":[]}]}]},{"type":"heading","depth":2,"payload":{"lines":[37,38]},"content":"数据结构(三要素)","children":[{"type":"list_item","depth":3,"payload":{"lines":[39,40]},"content":"逻辑结构","children":[{"type":"list_item","depth":4,"payload":{"lines":[41,42]},"content":"线性结构:线性表、栈、队列、串、数组...","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[42,43]},"content":"非线性结构:树、图、集合...","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[43,44]},"content":"集合:除了“同属于一个集合”的关系外,别无其他关系。","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[44,45]},"content":"线性结构:只存在一对一的关系。","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[45,46]},"content":"树形结构:存在一对多的关系。","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[46,47]},"content":"图状结构和网状结构:存在多对多的关系。","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[48,49]},"content":"存储(物理)结构","children":[{"type":"list_item","depth":4,"payload":{"lines":[50,51]},"content":"顺序存储","children":[{"type":"list_item","depth":5,"payload":{"lines":[52,53]},"content":"逻辑上相邻的元素存储在物理位置上也相邻的存储单元里,元素之间的关系由存储单元的邻接关系来体现","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[53,54]},"content":"优点","children":[{"type":"list_item","depth":6,"payload":{"lines":[55,56]},"content":"可以实现随机存取","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[56,57]},"content":"元素占用最少的存储空间","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[58,59]},"content":"缺点","children":[{"type":"list_item","depth":6,"payload":{"lines":[60,61]},"content":"只能使用相邻的一整块存储单元,依赖于物理结构相邻","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[61,62]},"content":"容易产生外部碎片","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[63,64]},"content":"链式存储","children":[{"type":"list_item","depth":5,"payload":{"lines":[65,66]},"content":"与顺序存储不同,链式存储不要求逻辑上相邻的元素在物理位置上也相邻","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[66,67]},"content":"优点","children":[{"type":"list_item","depth":6,"payload":{"lines":[68,69]},"content":"不会出现碎片现象","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[69,70]},"content":"充分利用所有存储单元","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[71,72]},"content":"缺点","children":[{"type":"list_item","depth":6,"payload":{"lines":[73,74]},"content":"除了存储元素外,还需要额外存储指针,会占用额外的存储空间(结合数据库索引学习)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[74,75]},"content":"链式存储,只能实现顺序存取,不能实现随机存取(指针的遍历)","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[76,77]},"content":"索引存储","children":[{"type":"list_item","depth":5,"payload":{"lines":[78,79]},"content":"存放数据元素和元素间关系的存储方式,在存储元素信息的同时,还需要建立附加的索引表","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[79,80]},"content":"优点","children":[{"type":"list_item","depth":6,"payload":{"lines":[81,82]},"content":"检索快(就好比字典有了目录,查询就很快了)","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[83,84]},"content":"缺点","children":[{"type":"list_item","depth":6,"payload":{"lines":[85,86]},"content":"增加了索引表,占用较多的存储空间(典型的空间换时间策略)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[86,87]},"content":"增加、删除数据时,需要对应修改索引表,花费更多时间","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[88,89]},"content":"散列(Hash)存储","children":[{"type":"list_item","depth":5,"payload":{"lines":[90,91]},"content":"根据元素的关键字直接通过散列(Hash)函数计算出元素的存储地址。","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[91,92]},"content":"优点","children":[{"type":"list_item","depth":6,"payload":{"lines":[93,94]},"content":"检索快","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[94,95]},"content":"添加、删除元素结点操作快(获取元素地址直接,整体时间就少了)","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[96,97]},"content":"缺点","children":[{"type":"list_item","depth":6,"payload":{"lines":[98,99]},"content":"非常依赖于散列函数","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[99,100]},"content":"会出现散列冲突(主要依赖与散列函数,散列函数不好就很容易出现散列冲突)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[100,101]},"content":"出现散列冲突时,解决冲突就会增加时间和空间上的开销","children":[]}]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[102,103]},"content":"数据的运算","children":[{"type":"list_item","depth":4,"payload":{"lines":[104,105]},"content":"运算的定义:针对逻辑结构,指出运算的功能","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[105,106]},"content":"运算的实现:针对存储结构,指出运算的具体操作步骤","children":[]}]}]},{"type":"heading","depth":2,"payload":{"lines":[107,108]},"content":"算法与算法评价","children":[{"type":"list_item","depth":3,"payload":{"lines":[109,110]},"content":"算法","children":[{"type":"list_item","depth":4,"payload":{"lines":[111,112]},"content":"定义","children":[{"type":"list_item","depth":5,"payload":{"lines":[113,114]},"content":"对特定问题求解步骤的一种描述","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[114,115]},"content":"是指令的有序集合","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[115,116]},"content":"每一条指令表示一个或多个操作","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[117,118]},"content":"五大特性","children":[{"type":"list_item","depth":5,"payload":{"lines":[119,120]},"content":"有穷性:执行有穷步后结束、在有穷时间内完成","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[120,121]},"content":"确定性:每条指令的含义明确,不会产生二义性,对相同的输入只能得出相同的结果","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[121,122]},"content":"可行性:算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[122,123]},"content":"输入:有零个或者多个输入,输入取决于某个特定的对象的集合","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[123,124]},"content":"输出:有一个或者多个输出,输出是和输入有着某种特定关系的量","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[125,126]},"content":"好算法追求的目标","children":[{"type":"list_item","depth":5,"payload":{"lines":[127,128]},"content":"正确性:需要正确的解决求解问题","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[128,129]},"content":"可读性:便于理解","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[129,130]},"content":"健壮性:在输入非法数据时,算法也能适当地做出反应或进行处理,而不会产生莫名奇妙的输出结果","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[130,131]},"content":"效率与低存储量需求","children":[{"type":"list_item","depth":6,"payload":{"lines":[132,133]},"content":"效率:算法执行的时间--->时间复杂度","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[133,134]},"content":"存储量需求:算法那执行过程中所有要的最大存储空间--->空间复杂度","children":[]}]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[135,136]},"content":"算法的评价","children":[{"type":"list_item","depth":4,"payload":{"lines":[137,138]},"content":"程序语句频度:程序语句在算法中被重复执行的次数","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[138,139]},"content":"时间复杂度O(n)","children":[{"type":"list_item","depth":5,"payload":{"lines":[140,141]},"content":"最坏空间复杂度:最坏情况下,算法的时间复杂度","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[141,142]},"content":"平均空间复杂度:所有可能输入实例在同等概率出现的情况下,算法的期望运行时间","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[142,143]},"content":"最好空间复杂度:最好的情况下,算法的时间复杂度","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[144,145]},"content":"空间复杂度S(n)","children":[{"type":"list_item","depth":5,"payload":{"lines":[146,147]},"content":"用来定义算法运行过程中需要耗费的存储空间","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[147,149]},"content":"渐进空间复杂度也被称为空间复杂度计数器变量,每访问一个结点,计算器加1,直到访问到空结点为止。","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[339,340]},"content":"时间复杂度:O(n)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[340,341]},"content":"判空条件","children":[{"type":"list_item","depth":7,"payload":{"lines":[342,343]},"content":"不带头结点的单链表L为空,判定条件是L=NULL。","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[343,344]},"content":"带头结点的单链表L为空,判空条件:L->next=NULL","children":[]}]}]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[345,346]},"content":"双链表","children":[{"type":"list_item","depth":4,"payload":{"lines":[347,348]},"content":"定义:在单链表的结点中增加了一个指向结点前驱的prior指针,由prior指针域、data数据域、next指针域三部分组成。","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[348,349]},"content":"基本特点","children":[{"type":"list_item","depth":5,"payload":{"lines":[350,351]},"content":"双链表仅仅在单链表的结点中增加了一个指向结点前驱的prior指针","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[351,352]},"content":"按值查找、按序号查找在单链表和双链表上的操作是相同的","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[352,353]},"content":"和单链表不同,插入、删除操作除了修改next指针域,双链表还需要修改prior指针域,确保不断链【重要】","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[354,355]},"content":"基本操作","children":[{"type":"list_item","depth":5,"payload":{"lines":[356,357]},"content":"插入结点","children":[{"type":"list_item","depth":6,"payload":{"lines":[358,359]},"content":"第一步:s->next=p->next","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[359,360]},"content":"第二步:p->next-prior=s","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[360,361]},"content":"第三步:s->prior=p","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[361,362]},"content":"第四步:p->next=s","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[362,363]},"content":"时间复杂度:O(1)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[363,364]},"content":"注意:结点p和s的前驱、后继指针要关联清楚,第一二步必须在第四步之前完成【重要】","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[365,366]},"content":"删除结点","children":[{"type":"list_item","depth":6,"payload":{"lines":[367,368]},"content":"第一步:p->next=q->next","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[368,369]},"content":"第二步:q->next->prior=p","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[369,370]},"content":"第三步:free(q) 释放结点内存空间","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[370,371]},"content":"时间复杂度:O(1)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[371,372]},"content":"注意:删除双链表结点p的后继结点的第一二步,顺序可换,及时释放内存空间【重要】","children":[]}]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[373,374]},"content":"循环链表","children":[{"type":"list_item","depth":4,"payload":{"lines":[375,376]},"content":"循环单链表","children":[{"type":"list_item","depth":5,"payload":{"lines":[377,378]},"content":"定义:在单链表的基础上,将最后一个结点(尾结点)的指针由NULL改为指向头结点,形成环。【单链表----->循环单链表】","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[378,379]},"content":"判断条件","children":[{"type":"list_item","depth":6,"payload":{"lines":[380,381]},"content":"不是判断头结点的指针是否为空,而是需要判断是否等于头指针","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[381,382]},"content":"表为空时,头结点的next指针域其实是指向自己","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[382,383]},"content":"结点的next指针指向自己,也就能判断表为空","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[384,385]},"content":"基本特点","children":[{"type":"list_item","depth":6,"payload":{"lines":[386,387]},"content":"在循环单链表中,尾结点*p的next指针域指向链表L(即:头结点),形成了闭环,不存在指针域为NULL的结点","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[387,388]},"content":"由于循环单链表是个环,在任何位置上的插入、删除操作都是等价的,不需要去判断是否是表尾","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[388,389]},"content":"单链表只能从头结点(表头结点)开始往后顺序遍历整个表,循环单链表可以从表中任意位置开始遍历整个链表,结点是等价的","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[389,390]},"content":"循环单链表可以抽象为时钟,形成的环是有顺序的","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[390,391]},"content":"频繁的表头和表尾操作,可以对循环单链表设置尾指针,而不设置头指针,明确尾指针r后,头指针即为:r->next ,减少头指针到尾指针间的遍历,时间复杂度:O(n)---->O(1)","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[392,393]},"content":"循环双链表","children":[{"type":"list_item","depth":5,"payload":{"lines":[394,395]},"content":"定义:在双链表的基础上,将尾结点的next指针指向头结点,将头结点的prior指针指向尾结点。【双链表----->循环双链表】","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[395,396]},"content":"判空条件","children":[{"type":"list_item","depth":6,"payload":{"lines":[397,398]},"content":"循环双链表为空时,头结点*p的prior指针和next指针都指向L","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[398,399]},"content":"同时满足","children":[{"type":"list_item","depth":7,"payload":{"lines":[400,401]},"content":"p->prior=L","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[401,402]},"content":"p->next=L","children":[]}]}]},{"type":"list_item","depth":5,"payload":{"lines":[403,404]},"content":"基本特点:从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点","children":[]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[405,406]},"content":"静态链表","children":[{"type":"list_item","depth":4,"payload":{"lines":[407,408]},"content":"定义:借助数组来描述线性表的链式存储结构,结点元素同样存在数据域data和指针域next","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[408,409]},"content":"需要注意","children":[{"type":"list_item","depth":5,"payload":{"lines":[410,411]},"content":"和普通的链表的指针域不同的是,静态链表的指针是结点元素的相对地址(数组下标),也称为游标,建议结合高级语言中数组的概念来理解;","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[411,412]},"content":"与顺序表一样,虽然静态链表属于链表,但是存储时需要预先分配一块连续的内存空间","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[412,413]},"content":"静态链表是通过数组游标来访问下一个结点元素","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[414,415]},"content":"特点","children":[{"type":"list_item","depth":5,"payload":{"lines":[416,417]},"content":"静态链表以next=-1作为结束的标志【尾结点】","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[417,418]},"content":"和动态链表相同,插入、删除操作不需要移动元素,只需要修改指针;","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[418,419]},"content":"总体来说,静态链表没有单链表使用方便,需要将整个链表存储在一块连续的内存空间中,内部的存储可以分散,通过指针构成链的关系","children":[]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[420,421]},"content":"零碎知识补充","children":[{"type":"list_item","depth":4,"payload":{"lines":[422,423]},"content":"无论是链表的插入还是删除操作,必须保证不断链【重要】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[423,424]},"content":"顺序存储结构可以随机存取也能顺序存取,链式结构只能进行顺序存取","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[424,425]},"content":"顺序存储方式同样适合图和树的存储,例如:满二叉树的顺序存储","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[425,426]},"content":"队列需要在表头删除元素,在表尾插入元素【先进先出】,采用带尾指针的循环单链表比较方便","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[426,427]},"content":"静态链表中的指针称为游标,指示下一个元素在数组中的下标","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[427,428]},"content":"静态链表用数组表示,需要预先分配较大的连续空间,同时具有一般链表的特点(插入、删除元素不需要移动元素)","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[428,429]},"content":"单链表设置头结点的","children":[{"type":"list_item","depth":5,"payload":{"lines":[430,431]},"content":"目的:方便运算","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[431,432]},"content":"好处","children":[{"type":"list_item","depth":6,"payload":{"lines":[433,434]},"content":"有头结点后,插入、删除数据元素的算法统一起来了,不需要判断是否在第一个元素之前插入或者删除第一个元素了","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[434,435]},"content":"不论链表是否为空,头指针是指向头结点的非空指针,链表的头指针不变,因此空链表和非空链表的处理也就统一起来了。","children":[]}]}]}]}]},{"type":"heading","depth":2,"payload":{"lines":[436,437]},"content":"顺序表和链表的比较","children":[{"type":"list_item","depth":3,"payload":{"lines":[438,439]},"content":"存取方式","children":[{"type":"list_item","depth":4,"payload":{"lines":[440,441]},"content":"顺序表支持顺序存取和随机存取","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[441,442]},"content":"链表只能从表头顺序存取元素,支持顺序存取","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[443,444]},"content":"逻辑结构与物理结构","children":[{"type":"list_item","depth":4,"payload":{"lines":[445,446]},"content":"顺序存储时,逻辑上相邻的元素,对应的物理存储位置也相邻【一定性】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[446,447]},"content":"链式存储时,逻辑上相邻的元素,对应的物理存储位置不一定相邻【可以相邻,也可以不相邻】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[447,448]},"content":"链式存储的逻辑关系通过指针链接表示","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[449,450]},"content":"时间复杂度","children":[{"type":"list_item","depth":4,"payload":{"lines":[451,452]},"content":"按值查找","children":[{"type":"list_item","depth":5,"payload":{"lines":[453,454]},"content":"顺序表无序的情况下,顺序表和链表的时间复杂度均为O(n);","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[454,455]},"content":"顺序表有序的情况下,顺序表的时间复杂度为O(log2n),链表为O(n);","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[456,457]},"content":"按序号查找","children":[{"type":"list_item","depth":5,"payload":{"lines":[458,459]},"content":"顺序表支持随机访问,时间复杂度为O(1);","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[459,460]},"content":"顺序表不支持随机访问,时间复杂度为O(n);","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[461,462]},"content":"插入、删除","children":[{"type":"list_item","depth":5,"payload":{"lines":[463,464]},"content":"顺序表平均需要移动半个表长的元素;","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[464,465]},"content":"链表只需要修改相应结点的指针域,不需要移动元素;","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[465,466]},"content":"链表结点除了数据域,还有指针域,在存储空间上比顺序存储需要更大的存储空间,付出更大的存储代价,存储密度不够大","children":[]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[467,468]},"content":"空间分配","children":[{"type":"list_item","depth":4,"payload":{"lines":[469,470]},"content":"顺序存储","children":[{"type":"list_item","depth":5,"payload":{"lines":[471,472]},"content":"静态分配","children":[{"type":"list_item","depth":6,"payload":{"lines":[473,474]},"content":"需要预先分配足够大的存储空间","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[474,475]},"content":"空间装满后不能扩充,存储新元素将出现内存溢出","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[475,476]},"content":"存储空间过大,顺序表后部闲置空间过多,造成内部碎片","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[476,477]},"content":"存储空间过小,会造成内存溢出","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[478,479]},"content":"动态分配","children":[{"type":"list_item","depth":6,"payload":{"lines":[480,481]},"content":"能够扩充存储空间","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[481,482]},"content":"需要移动大量元素,操作效率降低","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[482,483]},"content":"内存中没有更大块的连续存储空间,将会导致空间分配失败;","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[484,485]},"content":"链式存储","children":[{"type":"list_item","depth":5,"payload":{"lines":[486,487]},"content":"结点空间只在需要的时候申请分配","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[487,488]},"content":"只要内存由空间就可以分配,操作灵活、高效","children":[]}]}]}]},{"type":"heading","depth":2,"payload":{"lines":[489,490]},"content":"存储结构选取","children":[{"type":"list_item","depth":3,"payload":{"lines":[491,492]},"content":"基于存储的考虑","children":[{"type":"list_item","depth":4,"payload":{"lines":[493,494]},"content":"对线性表的长度和存储规模难以估计时,不宜采用顺序表存储","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[494,495]},"content":"链表不用事先估计存储规模,但存储密度较低","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[495,496]},"content":"链式存储结构的存储密度小于1,不要求连续的存储空间","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[497,498]},"content":"基于运算的考虑","children":[{"type":"list_item","depth":4,"payload":{"lines":[499,500]},"content":"随机存取","children":[{"type":"list_item","depth":5,"payload":{"lines":[501,502]},"content":"顺序表支持随机存取,按序号查找顺序表的时间复杂度为O(1),相对较好","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[502,503]},"content":"链表不支持随机存取,按序号查找链表的时间复杂度为O(n)","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[504,505]},"content":"插入、删除操作","children":[{"type":"list_item","depth":5,"payload":{"lines":[506,507]},"content":"顺序表的插入、删除操作,平均需要移动表中一半的元素,当表的数据量较大时,这种情况需要重点考虑的","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[507,508]},"content":"链表的插入、删除操作,也是需要找插入位置(前驱结点、后继结点),主要的操作还是比较操作,相对较好","children":[]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[509,510]},"content":"基于环境的考虑","children":[{"type":"list_item","depth":4,"payload":{"lines":[511,512]},"content":"顺序表容易实现,任何高级语言中都有数组类型","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[512,513]},"content":"链表操作是基于指针的,指针移动,相对复杂","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[514,515]},"content":"综合结论","children":[{"type":"list_item","depth":4,"payload":{"lines":[516,517]},"content":"通常比较稳定的线性表选择顺序存储","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[517,518]},"content":"频繁进行插入、删除操作的线性表,应该选择链式存储,动态性较强","children":[]}]}]}]},{"type":"heading","depth":1,"payload":{"lines":[519,520]},"content":"栈和队列","children":[{"type":"heading","depth":2,"payload":{"lines":[521,522]},"content":"栈【后进先出】","children":[{"type":"list_item","depth":3,"payload":{"lines":[523,524]},"content":"基础概念","children":[{"type":"list_item","depth":4,"payload":{"lines":[525,526]},"content":"定义: 只允许在一端进行插入或者删除操作的线性表。","children":[{"type":"list_item","depth":5,"payload":{"lines":[527,528]},"content":"后进先出","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[528,529]},"content":"明确栈是一种线性表","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[529,530]},"content":"限定栈只能在某一端进行插入或者删除操作","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[531,532]},"content":"栈顶:线性表允许进行插入和删除的一端","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[532,533]},"content":"栈底:不允许进行插入和删除的另外一端,是固定的","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[533,534]},"content":"空栈:不含任何元素的空表,也叫栈空","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[535,536]},"content":"基本操作","children":[{"type":"list_item","depth":4,"payload":{"lines":[537,538]},"content":"InitStack(&S): 初始化一个空栈S,栈顶指针初始化为-1","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[538,539]},"content":"StackEmpty(S): 判断一个栈是否为空,如果栈空则返回true,否则返回false","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[539,540]},"content":"Push(&S,x): 进栈,若栈未满,x进栈操作,插入到栈内成为新的栈顶元素","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[540,541]},"content":"Pop(&S,&x): 出栈,若栈非空,出栈操作,弹出栈顶元素,用指针x进行返回","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[541,542]},"content":"GetTop(S,&x): 读栈顶元素,若栈S非空,用x返回栈顶元素","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[542,543]},"content":"ClearStack(&S): 销毁栈,释放栈S占用的存储空间","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[544,545]},"content":"顺序存储结构","children":[{"type":"list_item","depth":4,"payload":{"lines":[546,547]},"content":"顺序栈","children":[{"type":"list_item","depth":5,"payload":{"lines":[548,549]},"content":"定义:栈的顺序存储,利用一组地址连续的存储单元存放自栈底到栈顶的所有元素,同时附加一个用来指向当前栈顶位置的指针","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[549,550]},"content":"顺序栈S【重要,栈顶指针初始化为-1】","children":[{"type":"list_item","depth":6,"payload":{"lines":[551,552]},"content":"栈顶指针S.top","children":[{"type":"list_item","depth":7,"payload":{"lines":[553,554]},"content":"初始时,S.top=-1","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[554,555]},"content":"栈顶元素:S.data[S.top]","children":[]}]},{"type":"list_item","depth":6,"payload":{"lines":[556,557]},"content":"进栈操作:栈不满时,栈顶+1,再进栈","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[557,558]},"content":"出栈操作:栈非空时,取栈顶元素,栈顶-1","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[558,559]},"content":"栈满条件:S.top=MaxSize-1","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[559,560]},"content":"栈空条件:S.top=-1","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[560,561]},"content":"栈长:S.top+1","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[561,562]},"content":"当对栈的最大使用空间估计不足时,容易出现栈上溢(外溢),需要主动向用户报告反馈,避免出现错误;","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[563,564]},"content":"栈顶指针初始化为0【更多是为-1】","children":[{"type":"list_item","depth":6,"payload":{"lines":[565,566]},"content":"入栈: S.data[S.top++]=x","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[566,567]},"content":"出栈: x=S.data[--S.top]","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[567,568]},"content":"同时, 栈空、栈满条件也会有变化","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[569,570]},"content":"基本运算","children":[{"type":"list_item","depth":6,"payload":{"lines":[571,572]},"content":"InitStack(&S): 初始化一个空栈S,栈顶指针初始化为-1","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[572,573]},"content":"StackEmpty(S): 判断一个栈是否为空,即:栈顶指针是否为-1,如果栈空则返回true,否则返回false","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[573,574]},"content":"Push(&S,x): 进栈,若栈未满,x进栈操作,插入到栈内成为新的栈顶元素。","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[574,575]},"content":"Pop(&S,&x): 出栈,若栈非空,出栈操作,弹出栈顶元素,用指针x进行返回。","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[575,576]},"content":"GetTop(S,&x): 读(获取)栈顶元素,若栈S非空,用x返回栈顶元素。","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[577,578]},"content":"共享栈","children":[{"type":"list_item","depth":5,"payload":{"lines":[579,580]},"content":"定义:利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一维存储空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶则向共享空间的中间延伸","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[580,581]},"content":"基础概念","children":[{"type":"list_item","depth":6,"payload":{"lines":[582,583]},"content":"两个栈(0、1号顺序栈)的栈顶指针都指向栈顶元素","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[583,584]},"content":"0号栈栈顶指针top=-1时,0号栈为空","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[584,585]},"content":"1号栈栈顶指针top=MaxSize时,1号栈为空","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[585,586]},"content":"当且仅当两个栈的栈顶指针相邻(top1-top0=1),可以判断共享栈栈满","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[587,588]},"content":"进栈【先移动指针,后赋值】","children":[{"type":"list_item","depth":6,"payload":{"lines":[589,590]},"content":"当0号栈进栈时,0号栈栈顶指针top0先加1后赋值","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[590,591]},"content":"当1号栈进栈时,0号栈栈顶指针top1先减1后赋值","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[592,593]},"content":"出栈【先赋值,后移动指针】","children":[{"type":"list_item","depth":6,"payload":{"lines":[594,595]},"content":"当0号栈进栈时,0号栈栈顶指针top0先赋值后减1","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[595,596]},"content":"当1号栈进栈时,0号栈栈顶指针top1先赋值后加1","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[597,598]},"content":"重要特性","children":[{"type":"list_item","depth":6,"payload":{"lines":[599,600]},"content":"共享栈能够更有效的利用存储空间,两个栈空间进行相互调节","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[600,601]},"content":"只有当这个存储空间(即:共享空间)被占满时才会发生上溢","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[601,602]},"content":"共享栈对存取效率没有什么影响,存取数据的时间复杂度都为O(1),在栈顶操作。","children":[]}]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[603,604]},"content":"链式存储结构","children":[{"type":"list_item","depth":4,"payload":{"lines":[605,606]},"content":"基本概念","children":[{"type":"list_item","depth":5,"payload":{"lines":[607,608]},"content":"链栈: 采用链式存储的栈","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[608,609]},"content":"栈满:对于链栈来说,是基于链式存储的,基本不存在栈满的情况,除非内存已经没有使用空间了","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[609,610]},"content":"栈空:对于空栈来说,链表原来的定义是头指针指向空,那么链栈的空其实就是top=NULL,链栈元素总数为0","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[610,611]},"content":"通常对于链栈来说,是不需要头结点的,当然也存在带头结点的链栈","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[612,613]},"content":"基础操作【基于单链表】","children":[{"type":"list_item","depth":5,"payload":{"lines":[614,615]},"content":"入栈","children":[{"type":"list_item","depth":6,"payload":{"lines":[616,617]},"content":"如果链栈不存在,则栈满,入栈操作失败,返回false;","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[617,618]},"content":"如果链栈存在,进行单链表的结点插入操作,移动指针,结点元素赋值,再将结点压入链栈中,移动链栈栈顶指针,最后链栈元素总数+1,返回true","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[619,620]},"content":"出栈","children":[{"type":"list_item","depth":6,"payload":{"lines":[621,622]},"content":"如果链栈不存在,或者为空栈,则无法进行出栈操作,返回false","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[622,623]},"content":"如果链栈满足出栈条件,则通过栈顶指针获取到链栈栈底结点,将其数据域赋值给变量e,移动栈顶指针指向待出栈元素的后继结点,同时释放待出栈元素的内存空间,链栈元素总数-1 ,出栈成功,返回true.","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[624,625]},"content":"基于单链表的链栈入栈、出栈操作,时间复杂度都为O(1)【重要】","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[626,627]},"content":"优点","children":[{"type":"list_item","depth":5,"payload":{"lines":[628,629]},"content":"便于多个栈共享存储空间","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[629,630]},"content":"不存在栈满上溢的情况,避免程序因溢出导致出错","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[630,631]},"content":"有效的提高存取效率","children":[]}]}]}]},{"type":"heading","depth":2,"payload":{"lines":[632,633]},"content":"队列【先进先出】","children":[{"type":"list_item","depth":3,"payload":{"lines":[634,635]},"content":"基本概念","children":[{"type":"list_item","depth":4,"payload":{"lines":[636,637]},"content":"队列:和栈一样,是一种操作受限制的线性表,只允许在表的一端进行插入,在表的另外一端进行删除,简称为队,常记作:Queue","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[637,638]},"content":"队头:允许进行删除操作的一端,也叫做队首,常记作:Front","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[638,639]},"content":"队尾:允许进行插入操作的一端,常记作:Rear","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[639,640]},"content":"空队列:不含任何元素的空表,注意这个表是指线性表","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[640,641]},"content":"入队: 向队列中插入元素,也叫做进队","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[641,642]},"content":"出队: 删除队列元素,也叫做离队","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[643,644]},"content":"基础操作","children":[{"type":"list_item","depth":4,"payload":{"lines":[645,646]},"content":"InitQueue(&Q): 初始化一个队列,构造空队列Q","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[646,647]},"content":"QueueEmpty(Q): 判断队列是否为空,队空返回true,否则返回false","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[647,648]},"content":"EnEmpty(&Q,x): 入队,如果队列Q未满,将x入队,成为新的队尾元素","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[648,649]},"content":"DeEmpty(&Q,&x): 出队,如果队列Q非空,删除队头元素,复制给x返回","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[649,650]},"content":"GetHead(Q,&x): 读取队头元素,如果队列Q非空,则将队头元素赋值给x","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[651,652]},"content":"顺序存储","children":[{"type":"list_item","depth":4,"payload":{"lines":[653,654]},"content":"顺序队列","children":[{"type":"list_item","depth":5,"payload":{"lines":[655,656]},"content":"队列的顺序实现是指分配一块连续的存储单元用来存放队列中的元素,并且附加两个指针","children":[{"type":"list_item","depth":6,"payload":{"lines":[657,658]},"content":"front指针: 指向队头元素的位置","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[658,659]},"content":"rear指针: 指向队尾元素的位置","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[660,661]},"content":"初始状态(队空条件):Q.front===Q.rear===0","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[661,662]},"content":"入队操作:队不满时,先赋值给队尾元素,再移动队尾指针+1","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[662,663]},"content":"出队操作: 队不空时,先取队头元素值,再移动队头指针+1","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[663,664]},"content":"Q.front===Q.rear===0,那能用Q.rear==MaxSize来表示队满嘛?【不行】","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[665,666]},"content":"循环队列","children":[{"type":"list_item","depth":5,"payload":{"lines":[667,668]},"content":"把顺序队列臆想为一个环状的空间,将存储队列元素的表从逻辑上看做为一个环","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[668,669]},"content":"初始时:Q.front=Q.rear=0","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[669,670]},"content":"队首指针进1: Q.front=(Q.front+1)%MaxSize","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[670,671]},"content":"队尾指针进1: Q.rear=(Q.rear+1)%MaxSize","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[671,672]},"content":"队列长度: (Q.rear+MaxSize-Q.front)%MaxSize","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[672,673]},"content":"除法取余运算(%)【解决顺序队列“上溢出”】问题","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[673,674]},"content":"如何区别队空还是队满?","children":[{"type":"list_item","depth":6,"payload":{"lines":[675,676]},"content":"方案一:牺牲一个单元来区分队空和队满","children":[{"type":"list_item","depth":7,"payload":{"lines":[677,678]},"content":"前提:队头指针在队尾指针在队尾指针的下一个位置作为队满标志【重要】","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[678,679]},"content":"队满条件:(Q.rear+1)%MaxSize==Q.front","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[679,680]},"content":"队空条件:Q.front==Q.rear","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[680,681]},"content":"队列中元素个数:(Q.rear+MaxSize-Q.front)%MaxSize","children":[]}]},{"type":"list_item","depth":6,"payload":{"lines":[682,683]},"content":"方案二:类型中增设表示元素个数的数据成员","children":[{"type":"list_item","depth":7,"payload":{"lines":[684,685]},"content":"直接和MaxSize去比较","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[685,686]},"content":"队空条件: Q.count=0","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[686,687]},"content":"队满条件: Q.count=MaxSize","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[687,688]},"content":"【注意】不论是队空还是队满,对会存在Q.front=Q.rear,这个可以通过前面方案一解决","children":[]}]},{"type":"list_item","depth":6,"payload":{"lines":[689,690]},"content":"方案三:类型中增设tag数据成员标记","children":[{"type":"list_item","depth":7,"payload":{"lines":[691,692]},"content":"通过添加tag标记的方式,区分队空还是队满","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[692,693]},"content":"tag0的情况下,如果因为删除导致Q.frontQ.rear,则队空;","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[693,694]},"content":"tag1的情况下,如果因为插入导致Q.frontQ.rear,则队满;","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[694,695]},"content":"tag的主要作用","children":[{"type":"list_item","depth":8,"payload":{"lines":[696,697]},"content":"在有元素入队的时候,设置tag=1","children":[]},{"type":"list_item","depth":8,"payload":{"lines":[697,698]},"content":"在有元素出队的时候,设置tag=0","children":[]}]}]}]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[699,700]},"content":"链式存储","children":[{"type":"list_item","depth":4,"payload":{"lines":[701,702]},"content":"链队列","children":[{"type":"list_item","depth":5,"payload":{"lines":[703,704]},"content":"链队列:和顺序队列一样,基于队列的链式表示叫做链队列,实际上为:一个同时带有队头指针和队尾指针的单链表","children":[{"type":"list_item","depth":6,"payload":{"lines":[705,706]},"content":"头指针指向队头结点","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[706,707]},"content":"尾指针指向队尾结点(单链表的最后一个结点)","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[708,709]},"content":"不带头结点链式队列","children":[{"type":"list_item","depth":6,"payload":{"lines":[710,711]},"content":"队空: linkQueue.frontNULL且linkQueue.rearNULL","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[711,712]},"content":"出队: 先判断队列是否为空,非空队列则取出队头元素,从链表中闪出去,队头指针Q.front指向下一个结点,如果出队的结此为尾结点,出队后队空,需要将Q.front和Q.rear都置为NULL","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[712,713]},"content":"入队: 建立一个新的结点,将新的结点插入到链表的尾部,修改队尾指针Q.rear指向新插入的结点。如果原队列为空,需要将队首指针也指向该结点","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[713,714]},"content":"【入队、出队操作,都需要考虑队空的情况下的特殊处理,不带头结点的队列导致队空队首和队尾指针都为NULL,麻烦】","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[715,716]},"content":"带头结点的链式队列","children":[{"type":"list_item","depth":6,"payload":{"lines":[717,718]},"content":"【复杂的入队、出队操作就统一起来】","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[718,719]},"content":"队空:Q.front==Q.rear,都指向头结点,一般数据域可以为空","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[719,720]},"content":"出队:判断队列是否为空,队列非空则在队首移动指针,将队首指针指向下一个元素。如果队列中就一个元素,则出队后将成为空队,Q.rear==Q.front,最后释放元素内存空间。","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[720,721]},"content":"入队:将元素插入队尾,移动队尾指针,即便为空队列入队,由于队列带有头结点,此时就很好的避免操作队首指针了。","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[721,722]},"content":"子主题 5","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[723,724]},"content":"特别注意","children":[{"type":"list_item","depth":6,"payload":{"lines":[725,726]},"content":"用单链表表示的链式队列非常适合频繁出队、入队、元素变化大的场景","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[726,727]},"content":"不存在队满情况,也不会出现溢出情况;","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[727,728]},"content":"链式队列不会出现存储分配不合理、“溢出”的情况,内存动态分配","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[729,730]},"content":"基本操作【带头结点】","children":[{"type":"list_item","depth":6,"payload":{"lines":[731,732]},"content":"队列初始化","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[732,733]},"content":"判断队空:Q.front==Q.rear","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[733,734]},"content":"入队【重要】","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[734,735]},"content":"出队【重要】","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[736,737]},"content":"双端队列","children":[{"type":"list_item","depth":5,"payload":{"lines":[738,739]},"content":"允许在两端都可以进行入队和出队操作的队列,元素的逻辑结构仍然是线性结构","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[739,740]},"content":"双端队列的两端分别称为前端和后端,两端都可以入队和出队","children":[{"type":"list_item","depth":6,"payload":{"lines":[741,742]},"content":"进队:前端进的元素排列在队列中后端进的元素的前面,后端进的元素排列在队列前端进的元素后面;","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[742,743]},"content":"出队:无论是前端还是后端出队,先出的的元素排列在后出的元素的前面","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[744,745]},"content":"输入受限的双端队列:允许在一端进行插入和删除操作,但在另外一端只允许进行删除的双端队列","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[745,746]},"content":"输出受限的双端队列:允许在一端进行插入和删除曹组,但在另外一端只允许进行插入的双端队列","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[747,748]},"content":"如果限定双端队列从某个断点插入的元素只能从该端点删除,那么此时的双端队列就演变为两个栈底相邻的栈","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[749,750]},"content":"补充","children":[{"type":"list_item","depth":5,"payload":{"lines":[751,752]},"content":"最适合用来链队的链表是:带队首指针和队尾指针的非循环单链表","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[752,753]},"content":"栈和队列的逻辑结构都是线性表,存储结构可能是顺序的(顺序栈、顺序队列),也可能是链式的(链栈、链队)","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[753,754]},"content":"不论是顺序存储还是链式存储,栈和队列都只能进行顺序存取(本质是线性表)。数组是可以做到随机存取(本质是顺序表)","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[754,755]},"content":"队列先进先出的特性:先进队列的元素先出队列,后进队列的元素后出队列","children":[]}]}]}]},{"type":"heading","depth":2,"payload":{"lines":[756,757]},"content":"应用","children":[{"type":"list_item","depth":3,"payload":{"lines":[758,759]},"content":"【栈】括号匹配","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[759,760]},"content":"【栈】表达式求值","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[760,761]},"content":"【栈】递归算法","children":[{"type":"list_item","depth":4,"payload":{"lines":[762,763]},"content":"定义: 如果在一个函数、过程或数据结构的定义中又应用了自身,那么这个函数、过程或者数据结构称为递归定义的,简称递归。","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[763,764]},"content":"递归通常把一个大型的复杂问题,层层转化为一个与原问题相似的规模较小的问题来求解","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[764,765]},"content":"斐波拉切数列算法优化","children":[{"type":"list_item","depth":5,"payload":{"lines":[766,767]},"content":"使用非递归实现","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[767,768]},"content":"使用空间换效率,例如:数组","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[768,769]},"content":"使用缓存,存放数据","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[770,772]},"content":"必须注意递归模型不能是循环定义,计算机图形学、工程计算中占有举足轻重的地位。","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[791,792]},"content":"数组定义:由n(n≥1)个相同类型的数据元素构成的有限序列。","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[792,793]},"content":"重要概念","children":[{"type":"list_item","depth":4,"payload":{"lines":[794,795]},"content":"【压缩存储】多个值相同的元素只分配一个存储空间,对零元素不分配存储空间---->节省存储空间。","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[795,796]},"content":"【特殊矩阵】具有很多相同矩阵元素或零元素,并且这些相同矩阵元素或零元素的分布有一定规律性的矩阵。","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[796,797]},"content":"【稀疏矩阵】矩阵元素个数s相对于矩阵中非零元素的个数t来说非常多、差距非常大,即s>>t的矩阵可以叫稀疏矩阵","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[798,799]},"content":"常见的特殊矩阵","children":[{"type":"list_item","depth":4,"payload":{"lines":[800,801]},"content":"对称矩阵","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[801,802]},"content":"上、下三角矩阵","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[802,803]},"content":"对角矩阵(带状矩阵)","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[803,804]},"content":"......","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[805,806]},"content":"注意","children":[{"type":"list_item","depth":4,"payload":{"lines":[807,808]},"content":"常规方法来存储稀疏矩阵,会想当浪费存储空间,所以稀疏矩阵只需要存储非零元素","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[808,809]},"content":"通常非零元素的分布是没有规律的,除了存储非零元素外,还需要存储元素所在位置的行和列","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[809,810]},"content":"寻相互存储三元组 <行标,列表,值>","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[810,811]},"content":"三元组的结点存储了行标(row)、列表(col)、值(value)三种信息,是主要用来存储稀疏矩阵的一种数据结构","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[812,813]},"content":"数组和线性表的关系","children":[{"type":"list_item","depth":4,"payload":{"lines":[814,815]},"content":"数组是线性表的推广","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[815,816]},"content":"数组一旦被定义,维数和维界就不再改变","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[816,817]},"content":"除了结构的初始化和销毁外,数组只会有存取元素和修改元素的操作","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[818,819]},"content":"数组的存储结构","children":[{"type":"list_item","depth":4,"payload":{"lines":[820,821]},"content":"按行优先","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[821,822]},"content":"按列优先","children":[]}]}]}]},{"type":"heading","depth":1,"payload":{"lines":[823,824]},"content":"树与二叉树","children":[{"type":"heading","depth":2,"payload":{"lines":[825,826]},"content":"树","children":[{"type":"list_item","depth":3,"payload":{"lines":[827,828]},"content":"定义","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[828,829]},"content":"术语","children":[{"type":"list_item","depth":4,"payload":{"lines":[830,831]},"content":"结点","children":[{"type":"list_item","depth":5,"payload":{"lines":[832,833]},"content":"祖先结点","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[833,834]},"content":"父子结点","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[834,835]},"content":"兄弟结点","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[835,836]},"content":"孩子结点","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[836,837]},"content":"子孙结点","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[837,838]},"content":"分支结点","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[838,839]},"content":"叶子结点(终端结点)","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[840,841]},"content":"度","children":[{"type":"list_item","depth":5,"payload":{"lines":[842,843]},"content":"结点的度","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[843,844]},"content":"树的度","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[845,846]},"content":"结点的深度、高度、层次","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[846,847]},"content":"有序树和无序树","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[847,848]},"content":"路径和路径长度","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[848,849]},"content":"森林","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[850,851]},"content":"性质","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[852,853]},"content":"二叉树","children":[{"type":"list_item","depth":3,"payload":{"lines":[854,855]},"content":"定义和特性","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[855,856]},"content":"存储结构","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[856,857]},"content":"二叉树遍历","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[857,858]},"content":"线索二叉树","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[859,860]},"content":"树和森林","children":[{"type":"list_item","depth":3,"payload":{"lines":[861,862]},"content":"存储结构","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[862,863]},"content":"树、森林与二叉树转换","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[863,864]},"content":"遍历","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[864,865]},"content":"并查集应用","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[866,867]},"content":"应用","children":[{"type":"list_item","depth":3,"payload":{"lines":[868,869]},"content":"二叉排序树","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[869,870]},"content":"平衡二叉树","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[870,871]},"content":"哈夫曼树","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[871,872]},"content":"哈夫曼编码","children":[]}]}]},{"type":"heading","depth":1,"payload":{"lines":[873,874]},"content":"图论","children":[{"type":"heading","depth":2,"payload":{"lines":[875,876]},"content":"定义","children":[]},{"type":"heading","depth":2,"payload":{"lines":[877,878]},"content":"基本操作","children":[{"type":"list_item","depth":3,"payload":{"lines":[879,880]},"content":"Adjacent(G,x,y)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[880,881]},"content":"Neighbors(G,x)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[881,882]},"content":"InsertVertex(G,x)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[882,883]},"content":"DeleteVertex(G,x)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[883,884]},"content":"AddEdge(G,x,y)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[884,885]},"content":"RemoveEdge(G,x,y)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[885,886]},"content":"FirstNeighbor(G,x)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[886,887]},"content":"NextNeighbor(G,x,y)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[887,888]},"content":"Get_edge_value(G,x,y)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[888,889]},"content":"Set_edge_value(G,x,y,v)","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[890,891]},"content":"存储及操作","children":[{"type":"list_item","depth":3,"payload":{"lines":[892,893]},"content":"邻接矩阵法","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[893,894]},"content":"邻接链表法","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[894,895]},"content":"十字链表","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[895,896]},"content":"邻接多重表","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[897,898]},"content":"图的遍历","children":[{"type":"list_item","depth":3,"payload":{"lines":[899,900]},"content":"广度优先搜索(BFS)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[900,901]},"content":"深度优先搜索(DFS)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[901,902]},"content":"连通性","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[903,904]},"content":"图的应用","children":[{"type":"list_item","depth":3,"payload":{"lines":[905,906]},"content":"最小生成树(MST)","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[906,907]},"content":"最短路径","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[907,908]},"content":"拓扑排序","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[908,909]},"content":"关键路劲","children":[]}]}]},{"type":"heading","depth":1,"payload":{"lines":[910,911]},"content":"查找","children":[{"type":"heading","depth":2,"payload":{"lines":[912,913]},"content":"基本概念","children":[{"type":"list_item","depth":3,"payload":{"lines":[914,915]},"content":"查找:在数据集合中寻找满足某种条件的数据元素的过程","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[915,916]},"content":"查找表(查找结构):用于查找的数据集合","children":[{"type":"list_item","depth":4,"payload":{"lines":[917,918]},"content":"数据元素(记录)的类型相同","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[918,919]},"content":"可以是一个数组或者链表等数据类型","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[919,920]},"content":"常见操作","children":[{"type":"list_item","depth":5,"payload":{"lines":[921,922]},"content":"查询某个特定元素是否存在","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[922,923]},"content":"检索满足条件的特定元素的各种属性","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[923,924]},"content":"数据元素插入","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[924,925]},"content":"数据元素删除","children":[]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[926,927]},"content":"静态查找表:不需要动态地修改查找表,与动态查找表对应","children":[{"type":"list_item","depth":4,"payload":{"lines":[928,929]},"content":"顺序查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[929,930]},"content":"折半查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[930,931]},"content":"散列查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[931,932]},"content":"....","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[933,934]},"content":"动态查找表:需要动态地插入或者删除的查找表","children":[{"type":"list_item","depth":4,"payload":{"lines":[935,936]},"content":"二叉排序树的查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[936,937]},"content":"散列查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[937,938]},"content":"....","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[939,940]},"content":"关键字:数据元素中唯一标识该元素的某个数据项的值","children":[{"type":"list_item","depth":4,"payload":{"lines":[941,942]},"content":"使用关键字查找,查找结果应该是【唯一的】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[942,943]},"content":"可以类比集合中不重复的key","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[943,944]},"content":"是不是想起了数据库的主键的概念????","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[945,946]},"content":"平均查找长度:所有查找过程中进行关键字的比较次数的平均值","children":[{"type":"list_item","depth":4,"payload":{"lines":[947,948]},"content":"查找长度:一次查找需要比较的关键字次数","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[948,949]},"content":"【是衡量查找算法效率的最主要的指标】","children":[]}]}]},{"type":"heading","depth":2,"payload":{"lines":[950,951]},"content":"顺序查找(线性查找)","children":[{"type":"list_item","depth":3,"payload":{"lines":[952,953]},"content":"主要用于在线性表中进行查找","children":[{"type":"list_item","depth":4,"payload":{"lines":[954,955]},"content":"一般的【无序线性表】的顺序查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[955,956]},"content":"按关键字【有序的顺序表】的顺序查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[956,957]},"content":"Tips:顺序表是指顺序存储的线性表,前面的有序才强调元素有序,顺序强调的是存储方式","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[958,959]},"content":"基于一般线性表的顺序查找","children":[{"type":"list_item","depth":4,"payload":{"lines":[960,961]},"content":"最直观的查找方式","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[961,962]},"content":"基本思想:从线性表的一端开始,逐个查询条件和关键字进行比对即可","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[962,963]},"content":"【重要】:哨兵的引入,可以避免很多不必要的判断语句,提高程序的效率","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[963,964]},"content":"平均查找长度","children":[{"type":"list_item","depth":5,"payload":{"lines":[965,966]},"content":"查找成功","children":[{"type":"list_item","depth":6,"payload":{"lines":[967,968]},"content":"第i个元素需要进行(n-i+1)次关键字比较","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[968,969]},"content":"概率相等的情况下:(n+1)/2","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[970,971]},"content":"查找失败【没有找到元素】","children":[{"type":"list_item","depth":6,"payload":{"lines":[972,973]},"content":"各关键字比较次数:(n+1)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[973,974]},"content":"平均查找长度:(n+1)","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[975,976]},"content":"综合分析","children":[{"type":"list_item","depth":5,"payload":{"lines":[977,978]},"content":"【缺点】:n较大时,平均查找长度较大,效率低","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[978,979]},"content":"【优点】:对数据元素的存储没有要求,顺序存储和链式存储都可行。对数据元素的有序性也没有要求","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[979,980]},"content":"【注意】:线性的链表只能进行顺序查找","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[981,982]},"content":"通常情况下,查找表中记录的查找概率并不相等","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[983,984]},"content":"基于有序表的顺序查找","children":[{"type":"list_item","depth":4,"payload":{"lines":[985,986]},"content":"预先已经知道表是按照关键字有序的,基于【二叉判定树】来查找,不用全部遍历----->【降低顺序查找失败的平均查找长度】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[986,987]},"content":"平均查找长度","children":[{"type":"list_item","depth":5,"payload":{"lines":[988,989]},"content":"查找成功","children":[{"type":"list_item","depth":6,"payload":{"lines":[990,991]},"content":"和一般线性表的顺序查找一样","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[991,992]},"content":"概率相等的情况下:(n+1)/2","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[993,994]},"content":"查找失败","children":[{"type":"list_item","depth":6,"payload":{"lines":[995,996]},"content":"到达是失败结点所查找的长度=失败结点父结点所在的层数【建议画画二叉判定树】","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[996,997]},"content":"查找概率相等时,平均查找长度:n/2 + n/(n+1)","children":[]}]}]},{"type":"list_item","depth":4,"payload":{"lines":[998,999]},"content":"【注意】:有序表的顺序查找中的线性表可以是链式存储结构的","children":[]}]}]},{"type":"heading","depth":2,"payload":{"lines":[1000,1001]},"content":"折半查找(二分查找)","children":[{"type":"list_item","depth":3,"payload":{"lines":[1002,1003]},"content":"【注意】仅仅适用于有序的顺序表","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1003,1004]},"content":"基本思想:首先与表中间位置元素的关键字比较,相等则查找成功,不相等则向左|向右继续与该部分中间元素比较......","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1004,1005]},"content":"核心思路:左右双指针,互相往中间靠拢,可以用二叉判定树来辅助思考","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1005,1006]},"content":"平均查找长度【计算非常重要】","children":[{"type":"list_item","depth":4,"payload":{"lines":[1007,1008]},"content":"查找成功","children":[{"type":"list_item","depth":5,"payload":{"lines":[1009,1010]},"content":"折半查找法查到给定值的比较次数最多不会超过【判定树】的高度","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1010,1011]},"content":"相等概率下,平均查找长度约等于log2(n+1) -1 ,【建议结合二叉树高度计算来理解】","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[1012,1013]},"content":"查找失败直接看例题.....","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[1014,1015]},"content":"综合分析","children":[{"type":"list_item","depth":4,"payload":{"lines":[1016,1017]},"content":"折半查找的时间复杂度为O(log2n), 平均情况下笔顺序查找O(n)的效率高","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1017,1018]},"content":"折半查找需要方便地定位查找区域---->存储结构必须具有【随机存取】的特性","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1018,1019]},"content":"【注意】仅仅适用于有序的顺序表,不适用链式存储结构,要求表按关键字有序排列","children":[]}]}]},{"type":"heading","depth":2,"payload":{"lines":[1020,1021]},"content":"分块查找(索引顺序查找)","children":[{"type":"list_item","depth":3,"payload":{"lines":[1022,1023]},"content":"具备顺序查找和折半查找的优点,既有动态结构,又能适用于快速查找","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1023,1024]},"content":"是不是有点【希尔排序】和【直接插入排序、折半插入排序】的发展效果?????","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1024,1025]},"content":"基本思想:查找表分成若干个子块","children":[{"type":"list_item","depth":4,"payload":{"lines":[1026,1027]},"content":"块内元素可以无序,【块之间必须有序】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1027,1028]},"content":"前一块的最大关键字永远小于后一块的最小关键字","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1028,1029]},"content":"【重要】:建立索引表,包含每个分块额最大关键字和第一个元素的地址(起始角标)","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1029,1030]},"content":"索引表按关键字有序排列","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[1031,1032]},"content":"查找方式","children":[{"type":"list_item","depth":4,"payload":{"lines":[1033,1034]},"content":"索引表:顺序查找或者折半查找","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1034,1035]},"content":"块内:顺序查找<----- 块内可以无序","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[1036,1037]},"content":"【直接看书】平均查找长度=索引查找平均长度+块内查找的平均长度","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[1038,1039]},"content":"【直接看书|视频,这部分我很迷糊】B树和B+树","children":[{"type":"list_item","depth":3,"payload":{"lines":[1040,1041]},"content":"B树(多路平衡查找树)","children":[{"type":"list_item","depth":4,"payload":{"lines":[1042,1043]},"content":"基础概念","children":[{"type":"list_item","depth":5,"payload":{"lines":[1044,1045]},"content":"阶:所有结点的孩子结点数的最大值","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1045,1046]},"content":"m阶B树(可能为空树)满足","children":[{"type":"list_item","depth":6,"payload":{"lines":[1047,1048]},"content":"树中每个结点至多有m棵子树(即至多包含m-1个关键字)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1048,1049]},"content":"如果根结点不是终端结点,至少有两棵子树","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1049,1050]},"content":"所有的叶结点都出现在同一个层次上,不带任何信息","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1050,1051]},"content":"....","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1052,1053]},"content":"B树是所有结点的平衡因子均为0的多路查找树","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[1054,1055]},"content":"基本操作","children":[{"type":"list_item","depth":5,"payload":{"lines":[1056,1057]},"content":"高度","children":[{"type":"list_item","depth":6,"payload":{"lines":[1058,1059]},"content":"B树的大部分操作需要的磁盘存取次数和B树的高度成正比","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1059,1060]},"content":"B树的高度不包括最后的不带任何信息的叶结点所处的那一层【有的参考书,也包含这部分】","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1060,1061]},"content":"【重要】如果每个结点重点额关键字个数达到最少,则容纳同样多关键字的B树的高度可以达到最大","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1061,1062]},"content":"....","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1063,1064]},"content":"查找","children":[{"type":"list_item","depth":6,"payload":{"lines":[1065,1066]},"content":"步骤","children":[{"type":"list_item","depth":7,"payload":{"lines":[1067,1068]},"content":"在B树中找结点【磁盘中进行】","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1068,1069]},"content":"在结点内找关键字【内存中进行】----> 采用【顺序查找法】或【折半查找法】","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1069,1070]},"content":"【Tips】B树常存储在磁盘上,在磁盘上找到目标节点后,将结点中的信息读入到内存","children":[]}]},{"type":"list_item","depth":6,"payload":{"lines":[1071,1072]},"content":"当查找到叶子结点,对应的指针为空指针,即树中没有对应的关键字","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1073,1074]},"content":"插入","children":[{"type":"list_item","depth":6,"payload":{"lines":[1075,1076]},"content":"插入操作比查找操作复杂多","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1076,1077]},"content":"步骤","children":[{"type":"list_item","depth":7,"payload":{"lines":[1078,1079]},"content":"定位","children":[{"type":"list_item","depth":8,"payload":{"lines":[1080,1081]},"content":"B树查找算法--->最底层中某个非叶结点","children":[]},{"type":"list_item","depth":8,"payload":{"lines":[1081,1082]},"content":"【重要】B树的插入关键字一定是插入到最底层的某个非叶结点内","children":[]}]},{"type":"list_item","depth":7,"payload":{"lines":[1083,1084]},"content":"插入","children":[{"type":"list_item","depth":8,"payload":{"lines":[1085,1086]},"content":"插入结点关键字个数小于m----> 直接插入","children":[]},{"type":"list_item","depth":8,"payload":{"lines":[1086,1087]},"content":"插入后检查插入结点内关键字个数,【大于m-1必须进行分裂】","children":[]}]},{"type":"list_item","depth":7,"payload":{"lines":[1088,1089]},"content":"【直接看书】】注意分裂的方法","children":[]}]}]},{"type":"list_item","depth":5,"payload":{"lines":[1090,1091]},"content":"删除(删除的关键字在终端结点)","children":[{"type":"list_item","depth":6,"payload":{"lines":[1092,1093]},"content":"直接删除关键字","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1093,1094]},"content":"兄弟够借","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1094,1095]},"content":"兄弟不够借","children":[]}]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[1096,1097]},"content":"B+树的概念","children":[{"type":"list_item","depth":4,"payload":{"lines":[1098,1099]},"content":"B+树是根据数据库的需要需要的一中B树的变形树","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1099,1100]},"content":"m阶的B+树需要满足的条件","children":[{"type":"list_item","depth":5,"payload":{"lines":[1101,1102]},"content":"每个分支结点最多有m棵子树(子结点)","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1102,1103]},"content":"结点的字树个数与关键字相等","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1103,1104]},"content":"非叶、根结点至少有两棵子树,其他分支结点至少有m/2(向上取整)棵子树","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1104,1105]},"content":"所有叶结点包含全部关键字及指向相应记录的指针","children":[{"type":"list_item","depth":6,"payload":{"lines":[1106,1107]},"content":"叶结点按关键字大小排列","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1107,1108]},"content":"相邻结点按大小顺序相互链接起来","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1109,1110]},"content":"【反复理解】所有的分支结点(理解为索引的索引)中仅仅包含它的各个子结点(下一级的索引快)中关键字的最大值和指向其子结点的指针","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1110,1111]},"content":"....","children":[]}]}]}]},{"type":"heading","depth":2,"payload":{"lines":[1112,1113]},"content":"散列(Hash)表","children":[{"type":"list_item","depth":3,"payload":{"lines":[1114,1115]},"content":"基本概念","children":[{"type":"list_item","depth":4,"payload":{"lines":[1116,1117]},"content":"散列函数:一个把查找表中的关键字映射成该关键字对应的地址(数组下标、索引、内存地址等)的函数","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1117,1118]},"content":"散列冲突:散列函数把两个或者多个不同关键字映射到同一个地址上,【冲突总是不可避免的】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1118,1119]},"content":"同义词:发生散列冲突(碰撞)的不同关键字","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1119,1120]},"content":"散列表:根据关键字直接访问的数据结构,是关键字和存储地址之间的一种直接映射关系","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1120,1121]},"content":"理想情况下,散列表中查找时间复杂度为O(1),与元素个数无关","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1121,1122]},"content":"基于【比较】的查找算法,查找效率取决于比较的次数","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1122,1123]},"content":"以上可以结合哈希加密、布隆过滤器等工作中的编程概念去比对学习....","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[1124,1125]},"content":"散列函数","children":[{"type":"list_item","depth":4,"payload":{"lines":[1126,1127]},"content":"构造散列函数,需要注意","children":[{"type":"list_item","depth":5,"payload":{"lines":[1128,1129]},"content":"散列函数的定义域【必须】要包含全部需要存储的关键字,值域的范围则依赖于散列表的大小或地址范围","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1129,1130]},"content":"散列函数计算出来的地址应该能【等概率、均匀的】分布在整个存储空间,尽可能减少散列冲突---> 【压测】","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1130,1131]},"content":"散列函数应该尽量简单,能够在较短时间内就计算出任一关键字对应的散列地址","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[1132,1133]},"content":"常用散列函数","children":[{"type":"list_item","depth":5,"payload":{"lines":[1134,1135]},"content":"直接定址法","children":[{"type":"list_item","depth":6,"payload":{"lines":[1136,1137]},"content":"直接去关键字的某个【线性函数值】为散列函数","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1137,1138]},"content":"优点","children":[{"type":"list_item","depth":7,"payload":{"lines":[1139,1140]},"content":"计算简单","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1140,1141]},"content":"【不会产生冲突】","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1141,1142]},"content":"适合关键字的分布【基本连续】的情况","children":[]}]},{"type":"list_item","depth":6,"payload":{"lines":[1143,1144]},"content":"缺点:关键字分布不连续时,空位较多,将造成存储空间的浪费","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1145,1146]},"content":"除留余数法","children":[{"type":"list_item","depth":6,"payload":{"lines":[1147,1148]},"content":"最简单、最常用的散列方法","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1148,1149]},"content":"关键在于【选择被除数P】,等概率进行映射,尽可能减少冲突的可能性","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1150,1151]},"content":"数字分析法","children":[{"type":"list_item","depth":6,"payload":{"lines":[1152,1153]},"content":"适用于已知的关键字集合","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1153,1154]},"content":"如果更换了关键字,就需要重新构造新的散列函数","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1155,1156]},"content":"平方取中法","children":[{"type":"list_item","depth":6,"payload":{"lines":[1157,1158]},"content":"取关键字的平方值的中间几位来作为散列地址","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1158,1159]},"content":"适用于关键字的每一位取值都不够均匀或小于散列地址所需要的位数","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1160,1161]},"content":"折叠法","children":[{"type":"list_item","depth":6,"payload":{"lines":[1162,1163]},"content":"将关键字分割成位数相同的几部分,取这几部分的叠加作为散列地址","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1163,1164]},"content":"关键字位数很多,每一位上数字分布大致均匀时,可以采用折叠法得到散列地址","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1165,1166]},"content":".....","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[1167,1168]},"content":"不同的情况,不同的散列函数会发挥不同的性能,无法笼统的说那种散列函数最好。散列函数的目标都是为了将产生冲突的可能性尽可能地降低","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[1169,1170]},"content":"处理冲突","children":[{"type":"list_item","depth":4,"payload":{"lines":[1171,1172]},"content":"【任何设计出来的散列函数都不可能绝对地避免冲突】,必须考虑在发生冲突时如何进行处理","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1172,1173]},"content":"处理方法","children":[{"type":"list_item","depth":5,"payload":{"lines":[1174,1175]},"content":"开放定址法","children":[{"type":"list_item","depth":6,"payload":{"lines":[1176,1177]},"content":"概念:可以存放新表项的空闲地址,既向它的同义词表项开放,也向它的非同义词表项开放","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1177,1178]},"content":"增量取值方法","children":[{"type":"list_item","depth":7,"payload":{"lines":[1179,1180]},"content":"线性探测法","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1180,1181]},"content":"平方探测法","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1181,1182]},"content":"再散列法(双散列法)","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1182,1183]},"content":"伪随机序列法","children":[]}]},{"type":"list_item","depth":6,"payload":{"lines":[1184,1185]},"content":"注意事项","children":[{"type":"list_item","depth":7,"payload":{"lines":[1186,1187]},"content":"不能随便【物理删除】表中已有元素,删除将会截断具有相同散列地址元素的查找地址,牵涉元素广","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1187,1188]},"content":"删除元素需要【单独做标记】,采用【逻辑删除】","children":[]},{"type":"list_item","depth":7,"payload":{"lines":[1188,1189]},"content":"逻辑删除会导致散列表表面上看上满的,实际上很多位置都是没有被利用的,【需要定期维护,将删除标记的\b元素物理删除】","children":[]}]}]},{"type":"list_item","depth":5,"payload":{"lines":[1190,1191]},"content":"拉链(链接)法","children":[{"type":"list_item","depth":6,"payload":{"lines":[1192,1193]},"content":"概念:为避免非同义词发生冲突,可以把所有的同义词存储在一个线性链表中【由散列地址唯一标识】","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1193,1194]},"content":"【重要】适用于经常进行插入和删除的情况","children":[]}]},{"type":"list_item","depth":5,"payload":{"lines":[1195,1196]},"content":"拉链法处理冲突时不存在聚集现象,用线性探测法处理冲突时容易产生聚集现象","children":[]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[1197,1198]},"content":"性能分析","children":[{"type":"list_item","depth":4,"payload":{"lines":[1199,1200]},"content":"装填因子:一个表的装满程度 =(表中的记录数)/ (散列表的长度)","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1200,1201]},"content":"查找效率取决于","children":[{"type":"list_item","depth":5,"payload":{"lines":[1202,1203]},"content":"散列函数","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1203,1204]},"content":"处理冲突的方法","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1204,1205]},"content":"【重要】装填因子","children":[]}]},{"type":"list_item","depth":4,"payload":{"lines":[1206,1207]},"content":"散列表的平均查找长度依赖于【散列表的填装因子】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1207,1208]},"content":"填装因子越大,表示装填的越“满”,发生冲突的可能性就越大","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1208,1209]},"content":"散列冲突导致散列表在查找过程中也是需要进行比较的。【查找效率仍然用平均查找长度来度量】","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1209,1210]},"content":"冲突的产生概率与装填因子(表中记录数和表长)的大小成正比","children":[]}]}]},{"type":"heading","depth":2,"payload":{"lines":[1211,1212]},"content":"模式匹配(字符串)","children":[{"type":"list_item","depth":3,"payload":{"lines":[1213,1214]},"content":"简单模式匹配","children":[{"type":"list_item","depth":4,"payload":{"lines":[1215,1216]},"content":"概念:第一个字符串(模式串)在第二串(主串)中的位置","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1216,1217]},"content":"基本过程:从主串指定字符开始(一般第一个)和模式串的第一个字符逐个比较....","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1217,1218]},"content":"时间复杂度:O(n*m),n、m分别为主串和模式串的长度","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[1219,1220]},"content":"【难点,直接看代码理解】KMP算法","children":[{"type":"list_item","depth":4,"payload":{"lines":[1221,1222]},"content":"【重要】是对简单模式匹配的改造,时间复杂度在O(n+m)的数量集上","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1222,1223]},"content":"【建议手动模拟】基本过程","children":[{"type":"list_item","depth":5,"payload":{"lines":[1224,1225]},"content":"整个匹配过程,没有进行指针回溯","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1225,1226]},"content":"每趟比较过程让子串向后滑动到一个合适位置, 让这个位置上的字符和主串中的那个字符比较","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1226,1227]},"content":"【重要】next数组的求解实际是对某个位置找到最长的公共前缀","children":[]}]}]},{"type":"list_item","depth":3,"payload":{"lines":[1228,1229]},"content":"总结比较","children":[{"type":"list_item","depth":4,"payload":{"lines":[1230,1231]},"content":"简单模式匹配时间复杂度:O(n*m)","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1231,1232]},"content":"KMP算法的时间复杂度为O(n+m)","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1232,1233]},"content":"一般情况下,简单模式匹配的实际执行时间可以近似到O(n+m)","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1233,1234]},"content":"【重要】KMP算法的重要特点是主串指针不回溯","children":[]}]}]}]},{"type":"heading","depth":1,"payload":{"lines":[1235,1236]},"content":"排序","children":[{"type":"heading","depth":2,"payload":{"lines":[1237,1238]},"content":"基本概念和定义","children":[{"type":"list_item","depth":3,"payload":{"lines":[1239,1240]},"content":"排序:重新排列表中的元素,让表中的元素能够满足按照关键字递增或者递减的过程","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1240,1241]},"content":"算法的稳定性【非常重要】","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1241,1242]},"content":"排序算法是否具有稳定性并不能衡量一个算法的优劣【重要】","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1242,1243]},"content":"内部排序:在排序期间元素全部存放在内存中的排序","children":[{"type":"list_item","depth":4,"payload":{"lines":[1244,1245]},"content":"关键字比较","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1245,1246]},"content":"移动元素","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1246,1247]},"content":"不是所有的内部排序算法都是基于比较操作的,例如:基数排序属于内部排序算法,但不是基于比较实现的","children":[]}]},{"type":"list_item","depth":3,"payload":{"lines":[1248,1249]},"content":"外部排序:在排序期间元素无法全部同时存放在内存中,必须在排序的过程中根据要求不断地在内、外存之间移动的排序。","children":[]}]},{"type":"heading","depth":2,"payload":{"lines":[1250,1251]},"content":"插入排序","children":[{"type":"list_item","depth":3,"payload":{"lines":[1252,1253]},"content":"基本思想:每次将一个待排序的记录,按关键字大小插入到前面已经排序好的子序列中,直到全部记录插入完成","children":[]},{"type":"list_item","depth":3,"payload":{"lines":[1253,1254]},"content":"直接插入排序","children":[{"type":"list_item","depth":4,"payload":{"lines":[1255,1256]},"content":"最简单、最直观的插入排序算法","children":[]},{"type":"list_item","depth":4,"payload":{"lines":[1256,1257]},"content":"性能分析","children":[{"type":"list_item","depth":5,"payload":{"lines":[1258,1259]},"content":"空间效率:仅仅使用到了常数个辅助单元,空间复杂度为O(1)","children":[]},{"type":"list_item","depth":5,"payload":{"lines":[1259,1260]},"content":"时间效率:排序过程中,需要向左侧有序子表中逐个插入元素,操作n-1次,每次操作都分为关键字比较和元素移动这两部分的次数非常依赖于待排序表的初始状态【重要】","children":[{"type":"list_item","depth":6,"payload":{"lines":[1261,1262]},"content":"最好的情况:元素已经有序,每个元素之需要比较一次,不用移动元素,O(n)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1262,1263]},"content":"最坏的情况:元素逆序,比较多次,移动多次,O(n^2)","children":[]},{"type":"list_item","depth":6,"payload":{"lines":[1263,1265]},"content":"平均情况:总的比较次数和总的移动次数均约等于为(n^2)/4