├── .gitignore
├── README.md
├── package.json
└── src
├── .vuepress
├── config.ts
├── navbar
│ └── navbar.ts
├── public
│ ├── assets
│ │ └── icon
│ │ │ ├── apple-icon-152.png
│ │ │ ├── chrome-192.png
│ │ │ ├── chrome-512.png
│ │ │ ├── chrome-mask-192.png
│ │ │ ├── chrome-mask-512.png
│ │ │ ├── guide-maskable.png
│ │ │ └── ms-icon-144.png
│ ├── favicon.ico
│ ├── logo.jpg
│ ├── logo.png
│ ├── logo.svg
│ └── logodark.png
├── sidebar
│ └── sidebar.ts
├── styles
│ ├── config.scss
│ ├── index.scss
│ └── palette.scss
└── theme.ts
├── README.md
├── algorithm-mandatory
├── README.md
├── array.md
├── backtrack.md
├── dfs.md
├── dp.md
├── handtearing.md
├── linklist
│ ├── 01.md
│ ├── 02.md
│ └── 03.md
├── other.md
├── rank.md
├── stark-queue
│ ├── 01.md
│ └── 02.md
├── string
│ ├── 01.md
│ └── 02.md
└── tree
│ ├── 01.md
│ ├── 02.md
│ └── 03.md
├── article
├── 02.md
└── README.md
├── cpp
├── README.md
├── compileAndLink.md
├── dataTypesAndTypeConversions.md
├── functionAndOperationOverloaders.md
├── inheritanceAndPolymorphism.md
├── memoryManagement.md
├── newFeatures.md
├── pointersAndReferences.md
├── rank.md
├── stl.md
└── summary.md
├── data-structure
└── rank.md
├── deliver
└── README.md
├── design
├── README.md
├── bigdata.md
├── design.md
└── rank.md
├── development-log
└── README.md
├── docker
└── rank.md
├── golang
├── README.md
├── gc.md
├── gmp.md
├── keyword.md
├── rank.md
└── summary.md
├── group
└── README.md
├── guide
└── README.md
├── hr
├── README.md
└── rank.md
├── intelligence
├── README.md
└── rank.md
├── interview
└── README.md
├── introduction
└── README.md
├── java
├── README.md
├── collection.md
├── concurrent.md
├── jvm.md
├── rank.md
├── spring.md
└── summary.md
├── k8s
├── README.md
└── rank.md
├── mysql
├── README.md
├── engine.md
├── indexing.md
├── lock.md
├── log.md
├── optimize.md
├── rank.md
├── summary.md
└── transaction.md
├── network
├── README.md
├── http.md
├── ip.md
├── rank.md
├── summary.md
└── tcp.md
├── nginx
├── README.md
└── rank.md
├── offical-delivery
└── README.md
├── os
├── README.md
├── concurrency.md
├── filesystem.md
├── memory-management.md
├── process.md
├── rank.md
├── serverprogramming.md
└── summary.md
├── project
└── rank.md
├── rabbitmq
├── README.md
├── apply.md
├── rank.md
└── summary.md
├── rank
└── README.md
├── recommendation-delivery
└── README.md
├── redis
├── README.md
├── application.md
├── colony.md
├── data-structure.md
├── persistence.md
├── rank.md
└── summary.md
├── resume
└── README.md
├── reward
└── README.md
├── start-learning
├── README.md
├── interview.md
├── resume.md
└── routine.md
└── website-contribution
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | node_modules/
3 | src/.vuepress/.cache/
4 | src/.vuepress/.temp/
5 | src/.vuepress/dist/
6 |
7 | .idea/
8 |
9 | package-lock.json
10 | pnpm-lock.yaml
11 | yarn.lock
12 | deploy.sh
13 | .github
14 | src/.env
15 | src/config.json
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | CSView | 计算机面试知识汇总
4 |
5 |
6 |
7 | 📖在线阅读网址👉:www.csview.cn
8 |
9 |
10 |
11 |
12 | 👁🗨CSView介绍
13 |
14 | CSView是一个互联网面试知识学习和汇总项目,包括**面试高频算法、系统设计、计算机网络、操作系统、cpp语言基础、Java语言基础、golang语言基础、MySQL、Redis、K8s、消息队列**等常见面试题。
15 |
16 | 与传统的学习网站不同的是,**CSView的内容来源于面经,并且网站和公众号会不断汇总面经内容来进行迭代**。真实的面试问什么,网站就写什么,这样更有助面试者了解面试情形。同时项目还会定期分享面试经验和互联网实用知识,帮助大家更好准备面试。
17 |
18 | 
19 |
20 |
21 |
22 | 🧑💻适用者
23 |
24 |
25 | **该项目适用于**:
26 |
27 | - 准备实习/校招面试的人
28 | - 面试前自查基础知识掌握程度的人
29 | - 社招补充基础的人
30 | - 喜欢抽象事物的人
31 | - 爱好仙子伊布的人
32 |
33 |
34 |
35 | 📚️学习
36 |
37 |
38 | 🟠刷题
39 |
40 | ### [👉面试必刷算法题](./src/algorithm-mandatory)
41 | ### [👉系统设计题](./src/design)
42 | ### [👉智力题](./src/intelligence)
43 | ### [👉HR面常见题](./src/hr)
44 |
45 |
46 |
47 |
48 | 🟢编程语言基础
49 |
50 | ### [👉cpp](./src/cpp/)
51 | ### [👉golang](./src/golang/)
52 | ### [👉java](./src/java/)
53 |
54 |
55 |
56 |
57 | 🔵计算机基础
58 |
59 | ### [👉计算机网络](./src/network/)
60 | ### [👉操作系统](./src/os/)
61 |
62 |
63 |
64 | 🔴数据库
65 |
66 | ### [👉MySQL](./src/mysql/)
67 | ### [👉Redis](./src/redis/)
68 |
69 |
70 | ⚫中间件
71 |
72 |
73 | ### [👉RabbitMQ](./src/rabbitmq/)
74 | ### [👉K8s](./src/k8s/)
75 | ### [👉Nginx](./src/nginx/)
76 |
77 |
78 |
79 |
80 |
81 | 💻项目来源
82 |
83 |
84 | 我叫zijing,是**CSView**的发起人。作为一个参加过22届秋招的人,我投递参加过**数十场校招面试,看过上百篇面经**,最后成功拿下了**字节、百度**等互联网公司的offer。我发现大多数互联网校招的准备方法仍有迹可循,围绕着**项目经历、语言基础、计算机网络,数据库、操作系统**等询问的基础知识(一般被称为八股文),在更为充分的准备下,明显会有更高面试通过率。
85 |
86 | 然而,现在互联网上存在大量低质量、错误频出、无用内容占多数的校招和八股文网站和文档分享,这会浪费面试准备者大量时间。为了避免时间浪费,让同学们把握面试中的要点内容,我找了几个朋友一起整理分享,于是CSView这个项目应运而生。
87 |
88 | 虽然现在有很多不足之处,但是好在开发迭代的速度很快,我们每天都在完善网站的内容,与面试准备者进行交流,帮助大家能找到更满意的工作。
89 |
90 | 当然,如果本站内容对你准备学习知识有帮助,您可以给一个**打赏(您的打赏将被放在网站的[贡献页面](https://www.csview.cn/website-contribution))**或者是**简单地去[GitHub](https://github.com/zijing2333/CSView)给项目点一个star**,作为对我们工作内容的认可。
91 |
92 |
93 |
94 |
95 |
96 | ✨项目特点
97 |
98 |
99 | **贴合面试**:网站的题目都是从数百篇面经中提取出来的**最常考**的题目,准备这些题目通常是性价比最高。我们并不会把诸如“**什么是数据库**”这类的问题放在网站上,一是没必要,二是浪费面试者的宝贵时间。
100 |
101 | **高质量回答**:针对高频次的题目网站都会给出一定的回答,回答介于书面语和口头语之间,既不失阅读时的严谨性,也不失理解上的简易性。
102 |
103 | **体验良好**:我们曾尝试过WordPress、MkDocs、Hexo等多种框架搭建网站,最后选择了功能完善且阅读体验更好的vuepress架构,并采用了vuepress-theme-hope主题。网站的**页面布局、内容分类、字体颜色、功能选配、代码块主题和图片配色**等都是精心调试过的,旨在带来更好的使用体验。
104 |
105 | **开源免费**:项目承诺所有内容完全免费,并且在[GitHub](https://github.com/zijing2333/CSView)您可以获取一切关于本站的内容。
106 |
107 | **共商共建**:您可以[开发日志](https://www.csview.cn/development-log/)看到网站更新工作和进展,我们会不断优化网站的每一处内容,网站内容也会根据面经和实际需求**每天更新**,及时修复存在的错误。任何人都可以参与到项目的建设中来,任何人都可以贡献内容到网站,贡献内容的人将会出现在网站的作者栏。
108 |
109 |
110 |
111 |
112 |
113 |
114 | ✍作者
115 |
116 | **枫长**:算法页面作者,某C9高校硕士,**曾在字节跳动和阿里云各实习两个月,力扣刷题800多道**,经常参加算法周赛,算法解题经验丰富。主要技术栈是C++。
117 |
118 |
119 |
120 | **LH**:985硕士,**22年秋招上岸字节核心部门**,是一个唱歌很好听的小哥哥。主要技术栈是C++。
121 |
122 |
123 |
124 | **jjd**:操作系统和C++页面作者,**国内top3计算机专业硕士在读**,本科专业top5%,曾获数学建模国奖一等奖。
125 |
126 |
127 |
128 | **xmy**:Java页面作者,985计算机硕士,曾在网易实习三个月,爱好打星际。主要技术栈是Java。
129 |
130 |
131 |
132 | **fawn**:CSView的图片绘制人,华五计算机专业,**高考680分+**,爱好睡觉。
133 |
134 |
135 |
136 | **小羊**:专业的图案创意设计者,爱好不加班。
137 |
138 |
139 |
140 | **子敬**:某985大学软件工程专业读研二,**仙子伊布爱好者**,喜欢读哲学、历史和养生学。主要技术栈是Golang。
141 |
142 |
143 |
144 |
145 | 🛠技术支持
146 |
147 | **开发测试**:[腾讯云服务器](https://github.com/zijing2333/CSView)
148 |
149 | **项目框架**:[vuepress2.0](https://v2.vuepress.vuejs.org/)
150 |
151 | **主题**:[vuepress-theme-hope](https://theme-hope.vuejs.press/)
152 |
153 | **代码托管和CDN加速**:[Vercel](https://vercel.com/)
154 |
155 | **图床**:[聚和图床](https://www.superbed.cn/)
156 |
157 | **图标**:[iconfont](https://www.iconfont.cn/)
158 |
159 | **页面语法**:MarkDown-Enhance
160 |
161 |
162 |
163 |
164 | ⚠️声明
165 |
166 | 网站为本人整合创作,禁止整合恶意搬运、分享,且严禁将网站内容整合搬运到任何公众号。未按要求注明来源的内容请联系我整改或者删除。
167 |
168 |
169 |
170 |
171 | 🦀特别鸣谢
172 |
173 | **特别感谢**[xiaolingcoding](https://xiaolincoding.com/)对本站创作和内容的支持,本站复用xiaolingcoding内容是为了带来更高质量的内容,同时也推荐大家去[xiaolingcoding](https://xiaolincoding.com/)系统学习计算机基础知识,这是一个质量极高的学习网站。
174 |
175 | **特别感谢**[Mr.Hope](https://mrhope.site/)(vue-theme-hope主题开发者)项目开发中提供的技术支持及问题解决方案。
176 |
177 |
178 |
179 |
180 | 📅未来计划
181 |
182 | - [ ] 面试题频次排序功能实现
183 | - [ ] 面经提交功能实现
184 | - [ ] 招聘汇总信息上线
185 | - [ ] 面经总结页面上线
186 | - [ ] 使用algolia重新构建网站索引
187 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vuepress-theme-hope-template",
3 | "version": "2.0.0",
4 | "description": "A project of vuepress-theme-hope",
5 | "license": "MIT",
6 | "type": "module",
7 | "scripts": {
8 | "docs:build": "vuepress build src",
9 | "docs:clean-dev": "vuepress dev src --clean-cache",
10 | "docs:dev": "vuepress dev src",
11 | "docs:deploy": "sh deploy.sh",
12 | "docs:update-package": "pnpm dlx vp-update"
13 | },
14 | "devDependencies": {
15 | "@vuepress/client": "2.0.0-beta.61",
16 | "vue": "^3.2.47",
17 | "vuepress": "2.0.0-beta.61",
18 | "vuepress-plugin-search-pro": "2.0.0-beta.193",
19 | "vuepress-theme-hope": "2.0.0-beta.193"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/.vuepress/config.ts:
--------------------------------------------------------------------------------
1 | import { defineUserConfig } from "vuepress";
2 | import theme from "./theme.js";
3 | import { searchProPlugin } from "vuepress-plugin-search-pro";
4 |
5 |
6 | export default defineUserConfig({
7 |
8 |
9 | // 部署站点基础路径
10 | base: "/",
11 |
12 | // 站点的语言
13 | lang: "zh-CN",
14 |
15 | // 站点的标题
16 | title: 'CSView计算机招聘知识分享',
17 |
18 | // 站点的描述
19 | description : 'CSView是一个互联网面试知识学习和汇总的八股文网站,包括面试高频算法、系统设计、计算机网络、操作系统、C++、Java、golang、MySQL、Redis、K8s、消息队列等常见面试题。',
20 |
21 |
22 | head: [
23 | // 自定义favicon
24 | ['link', { rel: 'icon', href: '/logo.png' }],
25 | // 流量统计脚本
26 | [
27 | "script",
28 | {},
29 | `var _hmt = _hmt || [];
30 | (function() {
31 | var hm = document.createElement("script");
32 | hm.src = "https://hm.baidu.com/hm.js?c902278b2f3d0bef22a61dce631ddecb";
33 | var s = document.getElementsByTagName("script")[0];
34 | s.parentNode.insertBefore(hm, s);
35 | })();`,
36 | ],
37 | [
38 | "script",
39 | {},
40 | `var _paq = window._paq = window._paq || [];
41 | /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
42 | _paq.push(['trackPageView']);
43 | _paq.push(['enableLinkTracking']);
44 | (function() {
45 | var u="//www.csguide.xyz/";
46 | _paq.push(['setTrackerUrl', u+'matomo.php']);
47 | _paq.push(['setSiteId', '1']);
48 | var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
49 | g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
50 | })();`,
51 | ],
52 | ],
53 |
54 | // 主题
55 | theme,
56 |
57 | // 插件
58 | plugins: [
59 |
60 | // 搜索插件
61 | searchProPlugin({
62 | // 索引全部内容
63 | indexContent: true,
64 | locales:{
65 | "/zh/": {
66 | cancel: "取消",
67 | placeholder: "搜索",
68 | search: "搜索",
69 | searching: "搜索中",
70 | select: "选择",
71 | navigate: "切换",
72 | exit: "关闭",
73 | history: "搜索历史",
74 | emptyHistory: "无搜索历史",
75 | emptyResult: "没有找到结果",
76 | loading: "正在加载搜索索引...",
77 | },
78 | },
79 |
80 | }),
81 | ],
82 | shouldPrefetch: true,
83 | });
84 |
--------------------------------------------------------------------------------
/src/.vuepress/navbar/navbar.ts:
--------------------------------------------------------------------------------
1 | import { navbar } from "vuepress-theme-hope";
2 |
3 | export const navBar = navbar([
4 |
5 | {
6 | text: "面试题",
7 | icon: "suanfaku",
8 | children: [
9 | {
10 | text: "力扣高频必刷题",
11 | icon: "zhongdianbiaozhu",
12 | link: "/algorithm-mandatory/",
13 |
14 | },
15 | {
16 | text: "智力题",
17 | icon: "dengpao",
18 | link: "/intelligence/",
19 |
20 | },
21 | {
22 | text: "设计题",
23 | icon: "sheji-xianxing",
24 | link: "/design/",
25 | },
26 | {
27 | text: "HR面常见题",
28 | icon: "mianshianpai",
29 | link: "/hr/",
30 | },
31 | ],
32 | },
33 |
34 | { text: "计算机网络", icon: "wangluo1", link: "/network/" },
35 |
36 | { text: "操作系统", icon: "caozuoxitong", link: "/os/" },
37 |
38 | {
39 | text: "数据库",
40 | icon: "data-Inquire-full",
41 | children: [
42 | {
43 | text: "MySQL",
44 | icon: "odbc-full",
45 | link: "/mysql/",
46 | },
47 | {
48 | text: "Redis",
49 | icon: "redis",
50 | link: "/redis/",
51 | },
52 | ],
53 | },
54 |
55 | {
56 | text: "编程语言基础",
57 | icon: "biancheng-01",
58 | children: [
59 | {
60 | text: "golang",
61 | icon: "Goyuyan",
62 | link: "/golang/",
63 | },
64 | {
65 | text: "c++",
66 | icon: "cyuyan",
67 | link: "/cpp/",
68 | },
69 | {
70 | text: "java",
71 | icon: "java",
72 | link: "/java/",
73 | },
74 | ],
75 | },
76 |
77 | {
78 | text: "中间件",
79 | icon: "gongju",
80 | children: [
81 | {
82 | text: "RabbitMQ",
83 | icon: "RabbitMQ",
84 | link: "/rabbitmq/",
85 | },
86 | {
87 | text: "Nginx",
88 | icon: "nginx",
89 | link: "/nginx/",
90 | },
91 | {
92 | text: "Kubernetes",
93 | icon: "kubernetes",
94 | link: "/k8s/",
95 | },
96 | ],
97 | },
98 |
99 | {
100 | text: "关于本站",
101 | icon: "guanyu",
102 | children: [
103 | {
104 | text: "项目介绍",
105 | icon: "jieshaoxinxi",
106 | link: "/introduction",
107 | },
108 | {
109 | text: "开发日志",
110 | icon: "rizhi",
111 | link: "/development-log",
112 | },
113 | {
114 | text: "网站贡献",
115 | icon: "gongxian",
116 | link: "/website-contribution",
117 | },
118 | ],
119 | },
120 | ]);
121 |
--------------------------------------------------------------------------------
/src/.vuepress/public/assets/icon/apple-icon-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/assets/icon/apple-icon-152.png
--------------------------------------------------------------------------------
/src/.vuepress/public/assets/icon/chrome-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/assets/icon/chrome-192.png
--------------------------------------------------------------------------------
/src/.vuepress/public/assets/icon/chrome-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/assets/icon/chrome-512.png
--------------------------------------------------------------------------------
/src/.vuepress/public/assets/icon/chrome-mask-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/assets/icon/chrome-mask-192.png
--------------------------------------------------------------------------------
/src/.vuepress/public/assets/icon/chrome-mask-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/assets/icon/chrome-mask-512.png
--------------------------------------------------------------------------------
/src/.vuepress/public/assets/icon/guide-maskable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/assets/icon/guide-maskable.png
--------------------------------------------------------------------------------
/src/.vuepress/public/assets/icon/ms-icon-144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/assets/icon/ms-icon-144.png
--------------------------------------------------------------------------------
/src/.vuepress/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/favicon.ico
--------------------------------------------------------------------------------
/src/.vuepress/public/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/logo.jpg
--------------------------------------------------------------------------------
/src/.vuepress/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/logo.png
--------------------------------------------------------------------------------
/src/.vuepress/public/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/.vuepress/public/logodark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zijing2333/CSView/225352361569e64b5983e18490bddeb0aefd4dd0/src/.vuepress/public/logodark.png
--------------------------------------------------------------------------------
/src/.vuepress/sidebar/sidebar.ts:
--------------------------------------------------------------------------------
1 | import { sidebar } from "vuepress-theme-hope";
2 |
3 | export const sideBar = sidebar({
4 |
5 | "/network/":[
6 |
7 | { text: "🟠 概述", link: "summary"},
8 | { text: "🔴 TCP和UDP", link: "tcp"},
9 | { text: "🔵 IP", link: "ip"},
10 | { text: "🟢 HTTP", link: "http"},
11 | ],
12 |
13 |
14 | "/mysql/":[
15 | { text: "🔴 概述", link: "summary"},
16 | { text: "🟤 事务", link: "transaction"},
17 | { text: "🔵 索引", link: "indexing"},
18 | { text: "🟢 锁", link: "lock"},
19 | { text: "🟣 存储引擎", link: "engine"},
20 | { text: "🟠 日志", link: "log"},
21 | { text: "🟡 优化", link: "optimize"},
22 | ],
23 |
24 | "/golang/":[
25 | { text: "🔴 概述", link: "summary"},
26 | { text: "🔵 关键字", link: "keyword"},
27 | { text: "🟢 GMP", link: "gmp"},
28 | { text: "🟡 垃圾回收", link: "gc"},
29 | ],
30 |
31 | "/redis/":[
32 | { text: "🔴 概述", link: "summary"},
33 | { text: "🔵 数据结构", link: "data-structure"},
34 | { text: "🟢 持久化", link: "persistence"},
35 | { text: "🟡 应用", link: "application"},
36 | { text: "🟣 集群", link: "colony"},
37 | ],
38 |
39 | "/cpp/":[
40 | { text: "🔴 C++基础概念和语法", link: "summary"},
41 | { text: "🟤 数据类型和类型转换", link: "dataTypesAndTypeConversions"},
42 | { text: "🔵 指针和引用", link: "pointersAndReferences"},
43 | { text: "🟢 函数和运算重载符", link: "functionAndOperationOverloaders"},
44 | { text: "🟣 继承和多态", link: "inheritanceAndPolymorphism"},
45 | { text: "🟠 内存管理", link: "memoryManagement"},
46 | { text: "🟡 编译和链接", link: "compileAndLink"},
47 | { text: "⚫ C++11/14/17/20新特性", link: "newFeatures"},
48 | { text: "⚪ STL", link: "stl"},
49 | ],
50 |
51 | "/java/":[
52 | { text: "🔴 基础", link: "summary"},
53 | { text: "🔵 集合", link: "collection"},
54 | { text: "🟢 并发", link: "concurrent"},
55 | { text: "🟡 JVM", link: "jvm"},
56 | { text: "🟣 Spring", link: "spring"},
57 | ],
58 |
59 | "/design/":[
60 | { text: "🔴 常见设计题", link: "design"},
61 | { text: "🔵 海量数据处理题", link: "bigdata"},
62 | ],
63 |
64 | "/rabbitmq/":[
65 | { text: "🔴 概述", link: "summary"},
66 | { text: "🔵 应用", link: "apply"},
67 | ],
68 |
69 | "/os/":[
70 | { text: "🔴 计算机系统基础", link: "summary"},
71 | { text: "🔵 并发", link: "concurrency"},
72 | { text: "🟢 内存管理", link: "memory-management"},
73 | { text: "🟡 进程与线程管理", link: "process"},
74 | { text: "🟣 文件系统", link: "filesystem"},
75 | { text: "🟠 服务器编程", link: "serverprogramming"},
76 | ],
77 |
78 |
79 |
80 | "/algorithm-mandatory/":[
81 | { text: "🔴 链表", link: "linklist"},
82 | { text: "🟤 树", link: "tree"},
83 | { text: "🔵 栈和队列", link: "stark-queue"},
84 | { text: "🟢 字符串", link: "string"},
85 | { text: "🟣 数组", link: "array"},
86 | { text: "🟠 动态规划", link: "dp"},
87 | { text: "🟡 DFS", link: "dfs"},
88 | { text: "⚫ 回溯", link: "backtrack"},
89 | { text: "⚪ 手撕", link: "handtearing"},
90 | { text: "🔶 其他", link: "other"},
91 | ],
92 |
93 |
94 |
95 | "/": [
96 | {
97 | text: "刷题",
98 | icon: "suanfaku",
99 | collapsible: true,
100 | children: [
101 | {
102 | text: "面试必刷算法题",
103 | icon: "zhongdianbiaozhu",
104 | link: "algorithm-mandatory",
105 |
106 | },
107 | {
108 | text: "智力题",
109 | icon: "dengpao",
110 | link: "intelligence",
111 |
112 | },
113 | {
114 | text: "设计题",
115 | icon: "sheji-xianxing",
116 | link: "design",
117 | },
118 | {
119 | text: "HR面常见题",
120 | icon: "mianshianpai",
121 | link: "hr",
122 | },
123 | ],
124 | },
125 |
126 |
127 | { text: "操作系统", icon: "caozuoxitong", link: "/os" },
128 | {
129 | text: "数据库",
130 | icon: "data-Inquire-full",
131 | collapsible: true,
132 |
133 | children: [
134 | {
135 | text: "MySQL",
136 | icon: "odbc-full",
137 | link: "/mysql",
138 | },
139 | {
140 | text: "Redis",
141 | icon: "redis",
142 | link: "/redis",
143 | },
144 | ],
145 | },
146 |
147 | {
148 | text: "编程语言基础",
149 | icon: "biancheng-01",
150 | collapsible: true,
151 |
152 | children: [
153 | {
154 | text: "golang",
155 | icon: "Goyuyan",
156 | link: "/golang",
157 | },
158 | {
159 | text: "c++",
160 | icon: "cyuyan",
161 | link: "/cpp",
162 | },
163 | {
164 | text: "java",
165 | icon: "java",
166 | link: "/java",
167 | },
168 | ],
169 | },
170 |
171 | {
172 | text: "中间件",
173 | icon: "gongju",
174 | collapsible: true,
175 | children: [
176 | {
177 | text: "RabbitMQ",
178 | icon: "RabbitMQ",
179 | link: "/rabbitmq",
180 | },
181 | {
182 | text: "Nginx",
183 | icon: "nginx",
184 | link: "/nginx",
185 | },
186 |
187 | {
188 | text: "Kubernetes",
189 | icon: "kubernetes",
190 | link: "/k8s",
191 | },
192 | ],
193 | },
194 |
195 | ],
196 | });
197 |
--------------------------------------------------------------------------------
/src/.vuepress/styles/config.scss:
--------------------------------------------------------------------------------
1 | // you can change config here
2 | $colors: #c0392b, #d35400, #f39c12, #27ae60, #16a085, #2980b9, #8e44ad, #2c3e50;
3 | // #7f8c8d !default;
4 | $code-light-theme: coy;
--------------------------------------------------------------------------------
/src/.vuepress/styles/index.scss:
--------------------------------------------------------------------------------
1 | // place your custom styles here
2 |
--------------------------------------------------------------------------------
/src/.vuepress/styles/palette.scss:
--------------------------------------------------------------------------------
1 | // you can change colors here
2 | // $theme-color: #096dd9;
3 | // $text-color:(
4 | // light:#212c37,
5 | // dark:#c9cad8,
6 | // );
7 |
8 | // $home-page-width: 70em;
9 | $theme-color: #2980b9;
10 | // $sidebar-width: 17rem;
11 | // $sidebar-mobile-width: 16rem;
12 | // $bg-color: (
13 | // light: #fdfafa,
14 | // dark: #1b1a1a,
15 | // );
16 | // $content-width: 50em;
17 | $border-color: (
18 | light: #ddd,
19 | dark: #444,
20 | );
21 |
22 | // .hero-info-wrapper .action-button {
23 | // // display: inline-block;
24 | // // overflow: hidden;
25 | // margin: 0.6rem;
26 | // padding: 0.5em 1.7rem;
27 | // border-radius: 3rem;
28 | // background: #67a52e;
29 | // color: #fffdfd;
30 | // font-size: 1.3rem;
31 | // transition: color var(--color-transition), color var(--color-transition), transform var(--transform-transition);
32 | // }
33 |
34 | // .hero-info-wrapper img {
35 | // display: block;
36 | // max-width: 100%;
37 | // max-height: 23rem;
38 | // margin: 0;
39 | // }
40 |
41 | .hero-info-wrapper .description {
42 | max-width: 35rem;
43 | color: #396794;
44 | font-weight: 500;
45 | font-size: 1.6rem;
46 | line-height: 1.3;
47 | }
48 |
49 | h1,
50 | h2,
51 | h3,
52 | h4,
53 | h5,
54 | h6 {
55 | font-weight: 600;
56 | line-height: 1.25;
57 | overflow-wrap: break-word;
58 | }
59 |
60 | .sidebar > .sidebar-links > li > .sidebar-link {
61 | font-size: 1em;
62 | }
63 |
64 | .hero-info-wrapper {
65 | .hero-info {
66 | .actions {
67 | .action-button {
68 | color: #2c3e50;
69 | transition-property: background-color;
70 | // transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
71 | // transition-duration: 150ms;
72 | }
73 | .action-button:nth-child(1) {
74 | background: #f9a8d4;
75 | }
76 | .action-button:nth-child(1):hover {
77 | background: #fbcfe8;
78 | }
79 | .action-button:nth-child(2) {
80 | background: #93c5fd;
81 | }
82 | .action-button:nth-child(2):hover {
83 | background: #bfdbfe;
84 | }
85 | .action-button:nth-child(3) {
86 | background: #7dd3fc;
87 | }
88 | .action-button:nth-child(3):hover {
89 | background: #bae6fd;
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/src/.vuepress/theme.ts:
--------------------------------------------------------------------------------
1 | import { hopeTheme } from "vuepress-theme-hope";
2 | import { navBar } from "./navbar/navbar";
3 | import { sideBar } from "./sidebar/sidebar";
4 |
5 |
6 |
7 | export default hopeTheme({
8 |
9 | // 导航栏中Logo的链接,404页面的返回首页链接
10 | home: '/',
11 |
12 | // logo
13 | logo: "/logo.png",
14 |
15 | // 夜间模式logo
16 | logoDark:"/logodark.png",
17 |
18 | // 项目仓库
19 | repo: "https://github.com/zijing2333/CSView",
20 |
21 | // 项目仓库标签
22 | repoLabel: "GitHub仓库",
23 |
24 | // 编辑此页
25 | editLink: true,
26 |
27 | // 文档源文件的仓库 URL
28 | docsRepo:"https://github.com/zijing2333/CSView",
29 |
30 | // 文档源文件的仓库分支
31 | docsBranch: "main",
32 |
33 | // 文档源文件存放在仓库中的目录名
34 | docsDir: 'src',
35 |
36 | // lastUpdated
37 | lastUpdated: true,
38 |
39 | // 域名
40 | hostname: "https://www.csview.cn",
41 |
42 | // 作者信息
43 | author: {
44 | name: "zijing2333",
45 | email: "944741457@qq.com",
46 | },
47 |
48 | favicon: '/logo.png',
49 |
50 | // 图标
51 | iconAssets: "//at.alicdn.com/t/c/font_3888455_yh47d67uz7k.css",
52 |
53 | // 面包屑导航
54 | breadcrumb:false,
55 |
56 | // 侧边栏
57 | sidebar:sideBar,
58 |
59 | // 导航栏
60 | navbar:navBar,
61 |
62 | // 隐藏打印按钮
63 | print: false,
64 |
65 | // 插件
66 | plugins: {
67 |
68 | // 评论插件
69 | comment: {
70 | /**
71 | * Using Waline
72 | */
73 | provider: "Waline",
74 | serverURL: "https://comment-3nup9yoof-zijing2333.vercel.app",
75 | requiredMeta: ['nick', 'mail'],
76 | meta: ['nick', 'mail'],
77 | comment: true,
78 | },
79 |
80 | mdEnhance: {
81 | align: true,
82 | attrs: true,
83 | chart: true,
84 | codetabs: true,
85 | container: true,
86 | tasklist: true,
87 | demo: true,
88 | echarts: true,
89 | figure: true,
90 | flowchart: true,
91 | gfm: true,
92 | imgLazyload: true,
93 | imgSize: true,
94 | include: true,
95 | katex: true,
96 | mark: true,
97 | mermaid: true,
98 | playground: {
99 | presets: ["ts", "vue"],
100 | },
101 | presentation: {
102 | plugins: ["highlight", "math", "search", "notes", "zoom"],
103 | },
104 | stylize: [
105 | {
106 | matcher: "Recommended",
107 | replacer: ({ tag }) => {
108 | if (tag === "em")
109 | return {
110 | tag: "Badge",
111 | attrs: { type: "tip" },
112 | content: "Recommended",
113 | };
114 | },
115 | },
116 | ],
117 | sub: true,
118 | sup: true,
119 | tabs: true,
120 | vPre: true,
121 | vuePlayground: true,
122 | },
123 | }
124 | });
125 |
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | icon: home
4 | title: 首页
5 | heroImage: /logo.png
6 | heroImageDark: /logodark.png
7 | heroText: CSView
8 | tagline: 一个互联网面试内容汇总和八股文学习的网站,让互联网面试不再成为困难~
9 |
10 | actions:
11 | - text: 开始学习 🧭
12 | link: /start-learning
13 | type: primary
14 |
15 | - text: 题频排序 💡
16 | link: /rank
17 |
18 | - text: 精品文章 📄
19 | link: /article
20 |
21 | features:
22 | - title: 使用指南
23 | icon: zhinanzhidao-xianxing
24 | details: 介绍网站的一些基本功能,阅读指南有助于提高学习效率
25 | link: /guide
26 |
27 | - title: 公众号&学习群
28 | icon: shuyi_qunliao
29 | details: 加入微信交流群跟各位互联网上岸同学交流,互相学习,一起进步。公众号会定期分享高质量面经解析
30 | link: /group
31 |
32 |
33 | - title: 支持网站
34 | icon: hongbao1
35 | details: 可以请作者喝一杯奶茶,或者去Github点一个免费的star
36 | link: /reward
37 |
38 |
39 |
40 |
41 | footer: 备案号:吉ICP备2023000735号-2
42 |
43 | ---
44 |
45 |
46 |
47 | 
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/algorithm-mandatory/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | title: 面试必刷算法题
4 | editLink: false
5 | comment: false
6 | ---
7 | ------
8 |
9 | ------
10 |
11 | ## :closed_book: 手撕
12 |
13 | #### [常见面试手撕题目总结](./handtearing.md)
14 |
15 |
16 |
17 | ## :green_book:链表
18 |
19 | #### 1️⃣[链表第一部分 1~7 题](./linklist/01.md)
20 |
21 | #### 2️⃣[链表第二部分 8~14 题](./linklist/02.md)
22 |
23 | #### 3️⃣[链表第三部分 15~20 题](./linklist/03.md)
24 |
25 |
26 |
27 |
28 |
29 | ## :blue_book:树
30 |
31 | #### 1️⃣[树第一部分 1~10 题](./tree/01.md)
32 |
33 | #### 2️⃣[树第二部分 11~20 题](./tree/02.md)
34 |
35 | #### 3️⃣[树第三部分 21~28 题](./tree/03.md)
36 |
37 |
38 |
39 | ## :orange_book:栈和队列
40 |
41 | #### 1️⃣[栈和队列第一部分 1~4 题](./stark-queue/01.md)
42 |
43 | #### 2️⃣[栈和队列第二部分 5~8 题](./stark-queue/02.md)
44 |
45 |
46 |
47 | ## :notebook:字符串
48 |
49 | #### 1️⃣[第一部分 1~6 题](./string/01.md)
50 |
51 | #### 2️⃣[第二部分 7~11 题](./string/02.md)
52 |
53 |
54 |
55 | ## :notebook_with_decorative_cover:[数组](./array.md)
56 |
57 | ## :ledger:[动态规划](./dp.md)
58 |
59 | ## :page_facing_up:[DFS](./dfs.md)
60 |
61 | ## :page_with_curl:[回溯](./backtrack.md)
62 |
63 | ## :bookmark_tabs:[其他](./other.md)
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/algorithm-mandatory/rank.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 面试算法题频排序
3 | pageInfo: false
4 | editLink: false
5 | sidebar: false
6 | ---
7 |
8 | ------
9 |
10 | ------
11 |
12 |
13 |
14 | ### 常见的排序算法 (3次)
15 |
16 | ### 3.无重复字符的最长子串(2次)
17 |
18 | ### 手撕单例模式(2次)
19 |
20 | ### 124.二叉树中的最大路径和(2次)
21 |
22 | ### 3.无重复字符的最长子串(2次)
23 |
24 | ### 多线程交替打印数字(2次)
25 |
26 | ### 1143.最长公共子序列(2次)
27 |
28 | ### 739.每日温度(1次)
29 |
30 | ### 手撕约瑟夫环(1次)
31 |
32 | ### 143. 重排链表(1次)
33 |
34 | ### 518.零钱兑换 II (1次)
35 |
36 | ### 43.字符串相乘 (1次)
37 |
38 | ### 59.螺旋矩阵 II (1次)
39 |
40 | ### 328.奇偶链表 (1次)
41 |
42 | ### 206.反转链表 (1次)
43 |
44 | ### 146.LRU 缓存(1次)
45 |
46 | ### 24.两两交换链表中的节点(1次)
47 |
48 | ### 25.K个一组翻转链表(1次)
49 |
50 | ### 209.长度最小的子数组(1次)
51 |
52 | ### 572.另一棵树的子树(1次)
53 |
54 | ### 141.环形链表(1次)
55 |
56 | ### 142.环形链表 II(1次)
57 |
58 | ### 二叉树BFS(1次)
59 |
60 | ### 常见排序算法时间复杂度(1次)
61 |
62 | ### 92.反转链表(1次)
63 |
--------------------------------------------------------------------------------
/src/article/02.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | pageInfo: false
4 | editLink: false
5 |
6 | ---
7 |
8 |
9 |
10 | 校招和实习,编程语言该怎么选择?
11 |
12 |
13 |
14 | 0️⃣ 前言
15 |
16 | 最近很多同学在准备面试,问的比较多的一个问题:
17 |
18 | “自己一直跟着学校课程按部就班地学习,各类编程语言都学的半斤八两,找工作或者准备实习的时候,选什么作为主语言好一点?”
19 | |
20 |
21 |
22 | 针对这个问题我谈一下看法。
23 |
24 |
25 |
26 | 1️⃣ 编程语言是不重要的
27 |
28 |
29 | 先说结论:校招的时候,选择哪门语言反而是不重要的。
30 |
31 | 招聘分为两个阶段:第一个阶段是你一点经验没有,正在找第一份实习;第二个阶段是你已经实习几个月,有了一定地经验,正式找工作。
32 |
33 | 针对第一阶段找实习:无论做的什么WebServer、秒杀系统、在线OJ平台、课设大作业,还是实验室做的种种水项目,绝大部分人的简历上东西在稍微有点经验的面试官眼里就是玩具。这里我说的是绝大部分人。
34 |
35 | 针对第二阶段正式找工作:我问了不少朋友,他们给我的反馈都是面试主要根据你的项目经验问,编程语言相关的八股问的蛮少的,这和我实际面试体验也是比较吻合的。可以理解为:项目有得聊,他问纯八股也挺没意思。
36 |
37 | 我有一个朋友他主要学的是go,面的也是go,拼多多、阿里云、抖音、快手各个厂顶配offer都有,工资非常可人。他在22年招聘环境如此恶劣的情况下拿到这么多好的工作,跟学了哪门编程语言关系其实不大,因为有不少公司要求进去转。根本原因是他有一段腾讯核心部门一年的高质量实习+个人解决问题能力非常强。
38 |
39 | 又比如我,在找实习和工作的时候一直都是用go来面试,面试中主要都是对着我的简历项目深挖,语言相关的问的很少。我在字节实习的时候,项目需求有什么就写什么,js、python、go都写;我的正式工作,进去之后也要更换技术栈,做的是底层,需要转C或者C++;未来要做什么,我自己也不确定。
40 |
41 | 所以我的建议是:花更多时间准备算法刷题、计算机网络、操作系统、数据结构、计算机组成原理、设计模式这些通用的东西,当你了解这些通用的东西之后,以后不同语言之间的技术迁移也会容易很多。
42 |
43 | **注意:这里说的不重要指的是面试内容占比不大,但是常见语言八股文该背还是要背:比如Java的HashMap底层原理、C++的虚函数、go的三色标记法和混合写屏障......**
44 |
45 |
46 |
47 | 2️⃣ 各类编程语言的对比
48 |
49 |
50 |
51 |
52 | Java
53 |
54 | 
55 |
56 |
57 | Java是目前国内第一编程语言,主要用于企业级应用开发、网站平台开发、移动领域的手机游戏和移动android开发,大数据生态也是Java的天下。几乎所有的交易网站(淘宝,天猫,京东等)和金融网站都是用Java开发的。
58 |
59 | **优点**:稳,Java虽然被喷卷上天,但是岗位却仍然是最多的,生态十分完善。太多国内公司为其背书了。
60 |
61 | **缺点**:要学的真的很多,不仅仅有Java基本的语言基础,还有衍生出的各种生态: Java基础、Java并发、JVM、MySQL、Redis、Spring、MyBatis、Kafka、Dubbo啥的,面试基本都会问一问。
62 |
63 |
64 | C++
65 |
66 | 
67 |
68 | C++主要用于游戏领域、办公软件、图形处理、网站、搜索引擎、图形界面层、关系型数据库、浏览器、软件开发、集成环境IDE等等。想学好不容易,市面上的岗位招聘数量仅次于Java,一般搞游戏开发的都要学,现在游戏公司的薪资不低所以这一块的收入也不差。嵌入式、底层这边用的C或者C++也很多。
69 |
70 | **优点**:没Java卷,但是难学。虽然难学但是一通百会。
71 |
72 | **缺点**:学习门槛高,上手慢。因为比较难,不同程序员写的C++程序层次不齐,质量难以保证。
73 |
74 |
75 | Python
76 |
77 | 
78 |
79 | 主要应用领域是爬虫、数据分析、自动化测试和机器学习,但也有一些中小企业在做自研的网站和app应用的时候用Python做后端开发。
80 |
81 | Python大多数是数据分析和测试岗位,这个语言学习难度本身是低的,但是如果你要搞人工智能那么机器学习领域的专业知识才是难啃的硬骨头,这一行对与学历的要求也会很高。
82 |
83 | **注意:没有经验背书不建议把python作为自己后端的主语言,要求最低的其实是要求最高的**
84 |
85 |
86 |
87 | Golang
88 |
89 | 
90 |
91 | go主要应用于区块链技术和后端服务器应用,云原生、微服务、Web表现也很好,现在很多厂后端服务开始用go重构了。go好上手,学习起来比Java和C++简单,能写出什么样的代码还是取决于刚才提到的编程内功。招聘需求数量比不上Java和C++。
92 |
93 | **优点**:简单易懂,面试要背的八股文比Java或者C++少;面向未来的语言,需求会越来越大。
94 |
95 | **缺点**:岗位少比Java或者C++少很多很多;按照专业对口的角度,去不上中大厂基本宣告着失业;短期内生态不是很完善。
96 |
97 |
98 |
99 | 3️⃣ 校招生该如何选择
100 |
101 | 该怎么选择编程语言来面试呢?我的想法是:多多益善,技术永无止境。很多人精力有限,学好一门都可能身心交瘁,还要打磨这门语言对应的生态和应用场景。学好指的是:对这门语言的底层有了解,会使用它解决实际问题。而不是停留于知道语法、输出个"Hello World"、写个IF-ELSE语句。精通一门比会用三门更有竞争力,校招少选择几门,把该语言相关的技术往深度和广度学。
102 |
103 | 做后端开发方向,Java、C++、golang选一门作为自己的主修语言即可,或者类似于Rust、C#等语言也可以,都有市场和岗位。选择哪个编程语言,找工作的简历要有对应技术栈的项目作为支持。
104 |
105 | 如果求稳,选C++或者Java,基本没有公司不要Java和C++的。想去传统国企或者是银行之类就选Java,因为这些企业的上层应用基本都是Java开发。
106 |
107 | 如果确定自己想进大厂并且不想学的很多,go是不错的选择。腾讯、阿里、京东、百度、华为各个大厂都要go,还有深信服、快手、虾皮这些厂也要go,小型企业和各类国企基本对go没需要,虾皮22年秋招也没招人。
108 |
109 | 
110 |
--------------------------------------------------------------------------------
/src/article/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | editLink: false
4 | comment: false
5 | ---
6 |
7 |
8 |
9 | ⭐️ 精品文章
10 |
11 |
12 |
13 | 🧭 学习路线
14 |
15 |
16 | ::: center
17 | ### [校招和实习,编程语言该怎么选?](./02.md)
18 |
19 | :::
20 |
21 |
--------------------------------------------------------------------------------
/src/cpp/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: C++
3 | pageInfo: false
4 | editLink: false
5 | comment: false
6 | ---
7 |
8 | ------
9 |
10 |
11 |
12 | ### [C++基础概念和语法](./summary.md)
13 |
14 | ### [数据类型和类型转换](./dataTypesAndTypeConversions.md)
15 |
16 | ### [指针和引用](./pointersAndReferences.md)
17 |
18 |
19 | ### [函数和运算重载符](./functionAndOperationOverloaders.md)
20 |
21 | ### [继承和多态](./inheritanceAndPolymorphism.md)
22 |
23 | ### [内存管理](./memoryManagement.md)
24 |
25 | ### [编译和链接](./compileAndLink.md)
26 |
27 | ### [C++11/14/17/20新特性](./newFeatures.md)
28 |
29 | ### [STL](./stl.md)
30 |
--------------------------------------------------------------------------------
/src/cpp/dataTypesAndTypeConversions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 数据类型和类型转换
3 | author: ["comewei","jjd","枫长","LH"]
4 | ---
5 |
6 | ### 1. 怎样判断两个浮点数是否相等?
7 |
8 | 在 C++ 中,直接使用等于运算符 `==` 来比较两个浮点数是否相等通常是**不安全**的,因为浮点数在计算机中的表示和计算可能会引入一定程度的误差。为了解决这个问题,可以使用一种称为“容差法”的方法来比较两个浮点数是否足够接近。以下是如何实现这种方法的详细介绍:
9 |
10 | **定义一个足够小的容差值(epsilon)**: 首先,需要定义一个足够小的正数作为容差值,它可以根据具体问题和精度需求来确定。通常,可以使用 C++ 标准库中的 `std::numeric_limits::epsilon()` 或 `std::numeric_limits::epsilon()` 来获取机器 epsilon,这是一个表示浮点数的最小可表示正数。
11 |
12 | ```cpp
13 | #include
14 |
15 | const double epsilon = std::numeric_limits::epsilon();
16 | ```
17 |
18 | **比较两个浮点数的差值是否小于容差值**: 接下来,计算两个浮点数之差的绝对值,然后将其与容差值进行比较。如果差值小于或等于容差值,可以认为这两个浮点数是相等的。
19 |
20 | ```cpp
21 | #include
22 |
23 | bool areEqual(double a, double b, double epsilon) {
24 | return std::abs(a - b) <= epsilon;
25 | }
26 | ```
27 |
28 | 这个函数接受两个浮点数 `a` 和 `b` 以及一个容差值 `epsilon`,然后计算它们之间的差值并与容差值进行比较。如果它们的差值小于或等于容差值,函数返回 `true`,表示两个浮点数可以认为是相等的。
29 |
30 |
31 |
32 | ### 2. 什么是隐式转换,如何消除隐式转换?
33 |
34 | C++ 中的隐式转换是指在不进行显式类型转换的情况下,编译器自动将一种类型转换为另一种类型。这通常发生在表达式中涉及多种类型的值时,或者在函数参数和返回值中使用了不同的类型。虽然隐式转换在某些情况下可以方便地将值从一种类型转换为另一种类型,但也可能导致意料之外的行为和错误。
35 |
36 | 以下是 C++ 中常见的隐式转换类型:
37 |
38 | - **整数提升**:将较小的整数类型(如 `char` 和 `short`)转换为较大的整数类型(如 `int` 或 `long`)。
39 | - **算术转换**:在算术表达式中将较低级别的算术类型转换为较高级别的算术类型。例如,将 `float` 转换为 `double`,或将 `int` 转换为 `float`。
40 | - **类型转换**:通过构造函数或转换函数将类类型转换为其他类类型。
41 | - **转换为布尔类型**:将算术类型、指针类型或类类型转换为布尔类型。
42 | - **函数参数和返回值的隐式转换**:当传递不同类型的实参给函数时,或者返回与函数声明中指定的返回类型不匹配的类型时,会发生隐式转换。
43 |
44 | 消除隐式转换的方法:
45 |
46 | - **使用显式类型转换**:通过使用 C++ 提供的显式类型转换操作符(如 `static_cast`、`reinterpret_cast`、`const_cast` 和 `dynamic_cast`)来明确指示需要进行的类型转换。
47 | - **使用 C++11 引入的 `explicit` 关键字**:在类构造函数或转换函数前添加 `explicit` 关键字,以防止编译器在需要类型转换时自动调用这些函数。这样可以避免不必要的隐式类型转换,提高代码的可读性和安全性。
48 | - **注意函数参数和返回值的类型**:确保函数参数和返回值的类型与调用和实现时所使用的类型匹配。这可以避免函数调用时发生意外的隐式类型转换。
49 | - **使用类型别名或 `auto` 关键字**:通过使用类型别名或 `auto` 关键字来推导类型,可以确保变量的类型与其初始化值相匹配,从而避免不必要的隐式类型转换。
50 |
51 |
52 |
53 | ### 3. C++四种强制转换?
54 |
55 | C++ 提供了四种强制类型转换运算符,分别是 `static_cast`、`dynamic_cast`、`const_cast`和 `reinterpret_cast`。它们分别用于不同的转换场景。
56 |
57 | **static_cast**:static_cast 是最常用的类型转换运算符,用于在相关类型之间进行转换,例如整数和浮点数、指向基类和指向派生类的指针等。static_cast 在编译时完成转换,如果转换无法进行,编译器会报错。示例:
58 |
59 | ```cpp
60 | double d = 3.14;
61 | int i = static_cast(d); // 浮点数转整数
62 | ```
63 |
64 | **dynamic_cast**:dynamic_cast 主要用于安全地在类的继承层次结构中进行指针或引用的向下转换(从基类到派生类)。在进行向下转换时,dynamic_cast 会在运行时检查转换是否合法。如果转换合法,返回转换后的指针;如果不合法,返回空指针(对于指针类型)或抛出异常(对于引用类型)。示例:
65 |
66 | ```cpp
67 | class Base { virtual void dummy() {} };
68 | class Derived : public Base { /* ... */ };
69 |
70 | Base* b = new Derived;
71 | Derived* d = dynamic_cast(b); // 合法的向下转换
72 | ```
73 |
74 | **const_cast**: const_cast 用于修改类型的 const 属性。常见用途包括:将常量指针转换为非常量指针、将常量引用转换为非常量引用等。需要注意的是,使用 const_cast 去掉 const 属性后修改原本为常量的对象是未定义行为。示例:
75 |
76 | ```cpp
77 | const int c = 10;
78 | int* p = const_cast(&c); // 去掉 const 属性
79 | ```
80 |
81 | **reinterpret_cast**: reinterpret_cast 提供低层次的类型转换,它通常用于不同类型的指针或引用之间的转换,以及整数和指针之间的转换。reinterpret_cast 可能导致与平台相关的代码,因此在使用时需要谨慎。示例:
82 |
83 | ```cpp
84 | int i = 42;
85 | int* p = &i;
86 | long address = reinterpret_cast(p); // 指针和整数之间的转换
87 | ```
88 |
89 |
90 |
91 |
92 |
93 | ### 4. auto和decltype的用法?
94 |
95 | `auto` 和 `decltype` 是 C++11 引入的两个类型推导关键字,它们用于在编译时根据表达式或变量的类型自动推导类型。
96 |
97 | `auto` 关键字用于自动推导变量的类型。它可以根据变量的初始化表达式来推导变量的类型。这在处理复杂类型、模板编程或者简化代码时非常有用。
98 |
99 | ```cpp
100 | int x = 42;
101 | auto y = x; // y 的类型自动推导为 int
102 |
103 | std::vector vec = {1, 2, 3};
104 | auto iter = vec.begin(); // iter 的类型自动推导为 std::vector::iterator
105 | ```
106 |
107 | 使用 `auto` 时必须提供初始化表达式,以便编译器推导类型。
108 |
109 | `decltype`: `decltype` 关键字用于根据表达式的类型推导出一个类型。与 `auto` 不同,`decltype` 不需要变量,它仅根据给定表达式的类型推导出相应的类型。
110 |
111 | ```cpp
112 | int x = 42;
113 | decltype(x) y = 10; // y 的类型推导为 int
114 |
115 | std::vector vec = {1, 2, 3};
116 | decltype(vec.begin()) iter = vec.begin(); // iter 的类型推导为 std::vector::iterator
117 | ```
118 |
119 | `decltype` 在泛型编程和模板元编程中非常有用,它可以帮助编写与表达式类型紧密相关的代码。
120 |
121 |
122 |
123 | ### 5. null与nullptr区别?
124 |
125 | `NULL` 和 `nullptr` 都是表示空指针的常量。
126 |
127 | **`NULL`**
128 |
129 | - `NULL` 在 C 和 C++ 中都可用,通常被定义为整数 0 或者类型为 `void*` 的空指针。
130 | - 在 C++ 中,`NULL` 的确切类型取决于实现。它可以是一个整数,也可以是一个 `void*` 类型的指针。
131 | - 由于 `NULL` 可能是一个整数,它可能会导致类型推断和函数重载的问题。
132 |
133 | **`nullptr`**
134 |
135 | - `nullptr` 是 C++11 引入的新关键字,专门用于表示空指针。
136 | - `nullptr` 的类型是 `std::nullptr_t`,它可以隐式转换为任何指针类型,但不能隐式转换为整数类型。
137 | - 使用 `nullptr` 可以避免 `NULL` 导致的类型推断和函数重载的问题。
138 |
139 | 下面是一个 `NULL` 和 `nullptr` 在函数重载时的例子:
140 |
141 | ```cpp
142 | void foo(int x) {
143 | std::cout << "foo(int)" << std::endl;
144 | }
145 |
146 | void foo(char* x) {
147 | std::cout << "foo(char*)" << std::endl;
148 | }
149 |
150 | int main() {
151 | foo(NULL); // 调用 foo(int),因为 NULL 被当作整数 0
152 | foo(nullptr); // 调用 foo(char*),因为 nullptr 可以隐式转换为 char* 类型
153 | }
154 | ```
155 |
156 | `NULL` 和 `nullptr` 都表示空指针,C++ 中建议使用 `nullptr`。因为 `nullptr` 是一个专门表示空指针的类型,可以避免 `NULL` 导致的类型推断和函数重载问题。
157 |
158 |
159 |
160 | ### 6. 左值引用与右值引用?
161 |
162 | 在C++中,左值和右值是表达式的两种基本分类。左值和右值引用是C++11引入的新特性,它们的主要目的是为了支持移动语义(move semantics)和完美转发(perfect forwarding)。
163 |
164 | **左值引用(Lvalue Reference)**: 左值引用是传统的C++引用,它绑定到左值上。左值(Lvalue)是一个表达式,可以位于赋值运算符的左侧或右侧。它们通常表示一个对象的内存地址,如变量或数组元素。
165 |
166 | 语法:
167 |
168 | ```cpp
169 | Type& reference_name = lvalue_expression;
170 | ```
171 |
172 | 例如:
173 |
174 | ```cpp
175 | int a = 42;
176 | int& ref_a = a; // 左值引用绑定到a上
177 | ```
178 |
179 | **右值引用(Rvalue Reference)**: 右值引用是C++11引入的新特性,它绑定到右值上。右值(Rvalue)是一个临时对象,不能位于赋值运算符的左侧,只能位于赋值运算符的右侧。右值引用主要用于实现移动语义,减少不必要的拷贝。
180 |
181 | 语法:
182 |
183 | ```cpp
184 | Type&& reference_name = rvalue_expression;
185 | ```
186 |
187 | 例如:
188 |
189 | ```cpp
190 | int&& ref_b = 42; // 右值引用绑定到临时值42上
191 | ```
192 |
193 |
194 |
195 | ### 7. 谈一谈 std::move 和 std::forward?
196 |
197 | `std::move` 和 `std::forward` 是 C++11 引入的两个实用函数,它们与右值引用和完美转发相关。
198 |
199 | **`std::move`**
200 |
201 | `std::move` 用于将左值转换为右值引用,从而允许移动语义。移动语义可以提高性能,因为它允许编译器在某些情况下避免复制,如临时对象或不再需要的对象。当使用 `std::move` 时,通常意味着对象的所有权被转移,原对象可能处于搬移后的状态。
202 |
203 | 例如,当使用 `std::vector` 时,可以通过 `std::move` 避免不必要的复制:
204 |
205 | ```cpp
206 | std::vector vec1 = {1, 2, 3};
207 | std::vector vec2 = std::move(vec1); // 移动 vec1 的内容到 vec2,避免复制
208 | ```
209 |
210 | 在这个例子中,`vec1` 的内容被移动到 `vec2`,`vec1` 变为空。需要注意的是,移动后原对象不应再被使用,除非已经对其重新赋值或初始化。
211 |
212 | **`std::forward`**
213 |
214 | `std::forward` 用于实现完美转发,它是一种将参数的类型和值类别(左值或右值)原封不动地传递给另一个函数的技术。这在泛型编程和模板中非常有用,特别是当我们不知道参数的确切类型和值类别时。
215 |
216 | 例如,以下代码实现了一个泛型包装函数,它将参数完美转发给另一个函数:
217 |
218 | ```cpp
219 | template
220 | auto wrapper(Func&& func, Args&&... args) -> decltype(func(std::forward(args)...)) {
221 | return func(std::forward(args)...);
222 | }
223 |
224 | int add(int a, int b) {
225 | return a + b;
226 | }
227 |
228 | int main() {
229 | int result = wrapper(add, 1, 2); // 完美转发参数 1 和 2 到 add 函数
230 | std::cout << result << std::endl;
231 | }
232 | ```
233 |
234 | 在这个例子中,`wrapper` 函数通过 `std::forward` 完美转发参数给 `add` 函数,保留了参数的类型和值类别。
235 |
236 |
237 |
238 | ### 8. const 和 #define 的区别?
239 |
240 | `const` 和 `#define` 都可以用于定义常量,但它们在C++中有一些重要的区别:
241 |
242 | - **类型检查**: `const` 是一个真正的常量,具有明确的数据类型,编译器会对其进行类型检查。而 `#define` 是预处理器的一部分,它不具备类型信息,编译器在进行预处理时将其替换为对应的值。这可能导致类型不匹配的问题。
243 |
244 | ```cpp
245 | const int const_value = 42;
246 | #define DEFINE_VALUE 42
247 | ```
248 |
249 | - **调试友好**: 由于 `const` 是编译器处理的,所以在调试时可以看到它的值和类型信息。但 `#define` 是预处理器处理的,在调试时不会显示宏的名称,只显示其替换后的值,这可能导致调试困难。
250 |
251 | - **作用域**: `const` 变量具有确定的作用域,例如在函数内部定义的 `const` 变量只在该函数内部可见。而 `#define` 宏定义没有作用域限制,除非使用 `#undef` 取消宏定义,否则宏将在整个编译单元内保持有效。这可能导致命名冲突和污染全局命名空间的问题。
252 |
253 | - **内存占用**: `const` 变量会占用内存空间,因为它们是真正的变量。而 `#define` 宏只在编译时进行文本替换,不会分配内存空间。
254 |
255 | - **使用场景**: `const` 常量更适用于基本数据类型、指针和对象。而 `#define` 宏定义除了用于定义常量外,还可以用于定义条件编译指令、函数宏等。
256 |
257 | 总之,在C++编程中,**推荐使用 `const` 来定义常量**,以获得更好的类型检查、调试支持和作用域控制。而 `#define` 宏定义适用于条件编译和特殊情况下的文本替换。
--------------------------------------------------------------------------------
/src/cpp/functionAndOperationOverloaders.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 函数和运算重载符
3 | author: ["comewei","jjd","枫长","LH"]
4 | ---
5 |
6 |
7 |
8 | ### 1. main函数有没有返回值?
9 |
10 | 在 C++ 中,main 函数确实有返回值。main 函数的返回值类型为 int,表示程序的退出状态。根据 C++ 标准,main 函数应具有以下两种形式之一:
11 |
12 | 1. 不带参数的 main 函数:
13 |
14 | ```cpp
15 | int main()
16 | {
17 | // 程序代码
18 | return 0;
19 | }
20 | ```
21 |
22 | 2. 带参数的 main 函数:
23 |
24 | ```cpp
25 | int main(int argc, char* argv[])
26 | {
27 | // 程序代码
28 | return 0;
29 | }
30 | ```
31 |
32 | 在这两种形式中,main 函数都有一个整数类型的返回值。通常,返回值 0 表示程序正常退出,非零值表示程序异常或错误。操作系统会捕获这个返回值,用于诊断程序的退出原因。如果 main 函数没有显式地包含 return 语句,编译器会自动插入一个`return 0;`作为默认返回值。因此,即使没有写 return 语句,main 函数仍然会返回一个整数值。
33 |
34 | ### 2. C++怎么实现一个函数先于main函数运行?
35 |
36 | **做法一:**
37 |
38 | `__attribute__((constructor))` 和 `__attribute__((destructor))` 是GCC编译器提供的特殊属性,用于指定某个函数在程序启动之前(主函数main()执行之前)或退出之后(main()函数执行结束后)自动执行。这些属性主要用于执行一些全局的初始化和清理操作。
39 |
40 | `__attribute__((constructor))`: 当一个函数被声明为 `__attribute__((constructor))` 时,这个函数将在程序启动之前(main()执行之前)自动执行。这对于执行一些全局的初始化操作非常有用。
41 |
42 | 例如:
43 |
44 | ```cpp
45 | #include
46 |
47 | void __attribute__((constructor)) init_function() {
48 | std::cout << "Before main()" << std::endl;
49 | }
50 |
51 | int main() {
52 | std::cout << "Inside main()" << std::endl;
53 | return 0;
54 | }
55 | ```
56 |
57 | 输出:
58 |
59 | ```cpp
60 | Before main()
61 | Inside main()
62 | ```
63 |
64 | `__attribute__((destructor))`: 当一个函数被声明为 `__attribute__((destructor))` 时,这个函数将在程序退出之后(main()函数执行结束后)自动执行。这对于执行一些全局的清理操作非常有用。
65 |
66 | 例如:
67 |
68 | ```cpp
69 | #include
70 |
71 | void __attribute__((destructor)) cleanup_function() {
72 | std::cout << "After main()" << std::endl;
73 | }
74 |
75 | int main() {
76 | std::cout << "Inside main()" << std::endl;
77 | return 0;
78 | }
79 | ```
80 |
81 | 输出:
82 |
83 | ```cpp
84 | Inside main()
85 | After main()
86 | ```
87 |
88 | 这些属性仅适用于GCC编译器,因此在使用其他编译器时,可能需要查找类似的功能。同时,这些功能在程序开发中应谨慎使用,以避免增加程序的复杂性。
89 |
90 | **做法二:**
91 |
92 | 在 C++ 中,可以使用全局对象的构造函数在 main 函数之前运行一些代码。全局对象的构造函数在 main 函数执行前调用,析构函数在 main 函数执行后调用。这里是一个简单的例子:
93 |
94 | ```cpp
95 | #include
96 |
97 | class MyPreMain {
98 | public:
99 | MyPreMain() {
100 | std::cout << "This is called before main()" << std::endl;
101 | }
102 |
103 | ~MyPreMain() {
104 | std::cout << "This is called after main()" << std::endl;
105 | }
106 | };
107 |
108 | // 定义一个全局对象
109 | MyPreMain my_pre_main;
110 |
111 | int main() {
112 | std::cout << "This is main()" << std::endl;
113 | return 0;
114 | }
115 | ```
116 |
117 | 输出如下:
118 |
119 | ```cpp
120 | This is called before main()
121 | This is main()
122 | This is called after main()
123 | ```
124 |
125 | 如上所示,MyPreMain 类的构造函数在 main 函数之前执行,析构函数在 main 函数之后执行。通过在全局对象的构造函数中执行所需的代码,可以在 main 函数之前完成一些操作。然而,这种方法应谨慎使用,因为全局对象的构造函数和析构函数的调用顺序可能受到编译器和链接器的影响。
126 |
127 | ### 3. 函数调用过程栈的变化,返回值和参数变量哪个先入栈?
128 |
129 | 在讲解 C++ 函数调用过程栈的变化之前,需要了解一下函数调用栈(Call Stack)的基本概念。函数调用栈是一种数据结构,用于存储函数调用的上下文信息,包括局部变量、参数、返回地址等。每次调用一个函数时,都会在栈上分配一个新的栈帧(Stack Frame),用于存储当前函数的上下文信息。函数执行完成后,栈帧会被销毁,控制权返回到调用者。
130 |
131 | C++ 函数调用过程栈的变化依赖于编译器和操作系统。常见的调用约定包括 cdecl、stdcall 和 fastcall 等。不同的调用约定有不同的参数传递方式和栈平衡策略。以下是一个简化的、通用的 C++ 函数调用过程栈变化示例:
132 |
133 | 1. 函数调用者将参数按照从右至左的顺序压入栈。
134 | 2. 函数调用者将返回地址压入栈。
135 | 3. 控制权转移到被调用函数。被调用函数为局部变量分配空间,将它们压入栈。
136 | 4. 被调用函数执行。
137 | 5. 被调用函数将返回值放入寄存器(如 EAX)或栈中的指定位置。
138 | 6. 被调用函数清理局部变量,销毁当前栈帧。
139 | 7. 控制权返回到函数调用者,恢复调用者的栈帧。
140 | 8. 函数调用者从栈中获取返回值。
141 | 9. 函数调用者清理参数。
142 |
143 | 请注意,这个过程并非固定不变,具体实现可能因编译器、操作系统和硬件平台而异。根据具体的调用约定,参数和返回值的传递方式也可能有所不同。一些调用约定可能会将参数通过寄存器传递,而不是通过栈。在通用示例中,参数是先入栈的。然后是返回地址。这是一个典型的调用过程,但实际实现可能会有所不同。总之,在研究函数调用过程时,需要考虑到编译器、操作系统和硬件平台的特性。
144 |
145 |
146 |
147 | ### 4. 谈一谈运算符重载?
148 |
149 | 运算符重载(Operator Overloading)是 C++ 中的一种特性,它允许程序员为自定义类型(如类和结构体)定义运算符的行为。这使得可以使用自然的语法来操作自定义类型的对象,提高了代码的可读性和易用性。运算符重载通过实现特殊的成员函数或非成员函数来完成。以下是一些关于运算符重载的详细介绍:
150 |
151 | 1. 成员函数和非成员函数:运算符重载可以通过实现类的成员函数或者非成员函数(通常是友元函数)来完成。例如,可以通过实现类的成员函数 `operator+` 来重载 `+` 运算符。
152 | 2. 可重载运算符:大多数 C++ 运算符都可以重载,例如 `+`、`-`、`*`、`/`、`%`、`==`、`!=`、`<`、`>`、`+=`、`-=` 等。然而,有一些运算符不能重载,如条件运算符(?:)、作用域解析运算符(::)和成员选择运算符(. 和 .*)。
153 | 3. 重载运算符的规则和限制:
154 | - 重载运算符的参数至少要有一个是自定义类型。这是为了防止对内置类型的运算符进行重载。
155 | - 不能更改运算符的优先级和结合性。
156 | - 重载运算符的数量和顺序应与原始运算符相同。
157 | - 除了赋值运算符(operator=)之外,运算符重载不能有默认实现。赋值运算符在未显式重载时会自动生成一个默认实现,执行逐成员赋值操作。
158 |
159 | 以下是一个运算符重载的示例,定义了一个简单的 `Complex` 类,用于表示复数,并重载了 `+` 和 `<<` 运算符:
160 |
161 | ```cpp
162 | #include
163 |
164 | class Complex {
165 | public:
166 | Complex(double real, double imag) : real_(real), imag_(imag) {}
167 |
168 | // 重载 + 运算符(成员函数)
169 | Complex operator+(const Complex& other) const {
170 | return Complex(real_ + other.real_, imag_ + other.imag_);
171 | }
172 |
173 | // 重载 << 运算符(友元函数)
174 | friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
175 | os << c.real_ << " + " << c.imag_ << "i";
176 | return os;
177 | }
178 |
179 | private:
180 | double real_;
181 | double imag_;
182 | };
183 |
184 | int main() {
185 | Complex c1(1.0, 2.0);
186 | Complex c2(3.0, 4.0);
187 | Complex c3 = c1 + c2;
188 |
189 | std::cout << "c1: " << c1 << std::endl;
190 | std::cout << "c2: " << c2 << std::endl;
191 | std::cout << "c3: " << c3 << std::endl;
192 |
193 | return 0;
194 | }
195 | ```
196 |
197 | 在使用运算符重载时,需要注意以下几点:
198 |
199 | - **保持运算符的语义**:在重载运算符时,应确保新的行为与原始运算符的语义保持一致。例如,`+` 运算符通常表示两个对象相加的操作,而 `==` 表示两个对象是否相等。不要为运算符赋予违反直觉或不符合通用规则的行为。
200 | - **谨慎使用运算符重载**:过度使用运算符重载可能导致代码难以阅读和理解。在某些情况下,使用普通的成员函数可能会更清晰地表达意图。只有当运算符重载能明显提高代码可读性和易用性时,才考虑使用它。
201 | - **确保运算符重载的效率**:在实现运算符重载时,要确保代码的效率。例如,在重载 `+` 运算符时,避免创建不必要的临时对象。在适当的情况下,可以考虑使用右值引用和移动语义来提高性能。
202 |
203 | ### 5. C++模板是什么,模板推导的规则?
204 |
205 | C++模板(Templates)是一种泛型编程机制,允许在编写代码时使用参数化类型,从而使得函数或类能够处理多种数据类型。这可以提高代码的可重用性和灵活性。模板分为两种:函数模板和类模板。
206 |
207 | **函数模板**:用于创建通用函数,适用于多种类型的参数。函数模板的定义使用 `template` 关键字,并在尖括号 `< >` 中指定类型参数。
208 |
209 | ```cpp
210 | template
211 | T add(const T& a, const T& b) {
212 | return a + b;
213 | }
214 | ```
215 |
216 | **类模板**:用于创建通用类,适用于多种类型的成员。类模板的定义也使用 `template` 关键字,并在尖括号 `< >` 中指定类型参数。
217 |
218 | ```cpp
219 | template
220 | class Stack {
221 | public:
222 | void push(const T& value);
223 | T pop();
224 | bool empty() const;
225 |
226 | private:
227 | std::vector data_;
228 | };
229 | ```
230 |
231 | 模板推导是编译器根据实际参数类型自动推导模板参数类型的过程。当使用模板函数时,大多数情况下无需显式指定模板参数类型,编译器会根据实际参数类型自动推导出相应的模板参数类型。以下是模板推导的规则:
232 |
233 | - **类型推导**:如果实际参数类型与模板参数类型相同,那么直接使用实际参数类型。例如,`add(1, 2)` 中的实际参数类型为 `int`,因此模板参数类型为 `int`。
234 | - **引用折叠**:当实际参数类型是引用时,编译器会进行引用折叠。例如,`add(a, b)` 中的实际参数类型为 `int&`,因此模板参数类型为 `int`。
235 | - **const 传递**:编译器会自动移除 `const` 限定符。例如,`add(1, 2)` 中的实际参数类型为 `const int`,因此模板参数类型为 `int`。
236 | - **数组和函数到指针的转换**:如果实际参数类型是数组或函数,编译器会将其转换为指针。例如,`add(arr1, arr2)` 中的实际参数类型为 `int[]`,因此模板参数类型为 `int*`。
237 | - **无法推导的情况**:有些情况下,编译器无法推导出模板参数类型。例如,当实际参数类型不一致时(如 `add(1, 2.0)`),或者当实际参数类型与模板参数类型之间存在多层间接关系时。在这些情况下,需要显式指定模板参数类型。
238 |
239 | ### 6. 模板类和模板函数的区别是什么?
240 |
241 | **实现目标**
242 |
243 | - 模板类:模板类主要用于创建具有通用数据成员和成员函数的类。通过参数化类型,模板类可以在多种类型之间复用相同的代码。常见的例子是容器类,如 `std::vector` 和 `std::list`。
244 | - 模板函数:模板函数主要用于创建通用的、适用于多种数据类型的函数。它们通常用于实现独立于类型的算法,如排序、查找等。例如,`std::sort` 和 `std::find` 都是模板函数。
245 |
246 | **定义方式**
247 |
248 | - 模板类:模板类使用 `template` 关键字和尖括号 `< >` 来定义类型参数。类型参数紧跟在 `template` 关键字之后,然后是类定义。
249 |
250 | ```cpp
251 | template
252 | class MyClass {
253 | // 类的成员定义
254 | };
255 | ```
256 |
257 | - 模板函数:模板函数也使用 `template` 关键字和尖括号 `< >` 来定义类型参数。类型参数紧跟在 `template` 关键字之后,然后是函数定义。
258 |
259 | ```cpp
260 | template
261 | T myFunction(T a, T b) {
262 | // 函数实现
263 | }
264 | ```
265 |
266 | **使用方式**
267 |
268 | - 模板类:在使用模板类时,需要为其指定类型参数。类型参数在类名之后的尖括号 `< >` 中提供。例如,`std::vector` 表示一个存储 `int` 类型元素的向量。
269 | - 模板函数:当调用模板函数时,通常无需显式指定类型参数。编译器会根据实际参数类型自动推导出相应的模板参数类型。例如,调用 `myFunction(1, 2)` 时,编译器会自动推导出模板参数类型为 `int`。
270 |
271 | ### 7. 函数模板实现机制?
272 |
273 | **定义函数模板**
274 |
275 | 函数模板的定义以 `template` 关键字开始,后面跟尖括号 `< >`,其中包含一个或多个类型参数。类型参数通常使用 `typename` 或 `class` 关键字声明。接下来是函数的声明和实现。
276 |
277 | ```cpp
278 | template
279 | T max(const T& a, const T& b) {
280 | return a > b ? a : b;
281 | }
282 | ```
283 |
284 | 在这个例子中定义了一个名为 `max` 的函数模板,它接受两个类型为 `T` 的参数,并返回较大的那个。
285 |
286 | **实例化函数模板**
287 |
288 | 当调用函数模板时,编译器会根据实际参数的类型自动推导出相应的模板参数类型。然后,编译器会为每个不同的模板参数类型生成一个具体的函数实例。这个过程称为模板实例化。
289 |
290 | ```cpp
291 | int main() {
292 | int a = 1, b = 2;
293 | double x = 3.0, y = 4.0;
294 |
295 | int c = max(a, b); // 实例化为 int 类型的 max 函数
296 | double z = max(x, y); // 实例化为 double 类型的 max 函数
297 | }
298 | ```
299 |
300 | 在这个例子中,分别调用了 `max` 函数模板的 `int` 版本和 `double` 版本。编译器会为每个版本生成相应的函数实例。
301 |
302 | **模板代码生成**
303 |
304 | 在编译过程中,编译器会为每个不同的函数模板实例生成相应的目标代码。这些代码在链接阶段被合并到最终的可执行文件中。模板代码的生成可能会导致代码膨胀,因为对于每个不同的模板参数类型,编译器都会生成一个新的函数实例。为了减小这种影响,编译器通常会进行一定程度的优化,以减少生成的代码的大小。
--------------------------------------------------------------------------------
/src/cpp/memoryManagement.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 内存管理
3 | author: ["comewei","jjd","枫长","LH"]
4 | ---
5 |
6 |
7 |
8 | ### 1. 大端序与小端序?
9 |
10 | 大端序(Big-endian)和小端序(Little-endian)是计算机存储多字节数据类型(如整数、浮点数等)时使用的两种字节序。它们描述了多字节数据在内存中的存储顺序。不同的硬件架构和操作系统可能采用不同的字节序,这在跨平台通信和数据交换时可能导致问题。
11 |
12 | - 大端序(Big-endian): 在大端序中,数据的高位字节(最重要的字节)存储在较低的内存地址中,而数据的低位字节(最不重要的字节)存储在较高的内存地址中。换句话说,字节序是从高位到低位。例如,32位整数 `0x12345678` 在大端序中的存储顺序是:
13 |
14 | ```cpp
15 | 内存地址: 0x01 0x02 0x03 0x04
16 | 存储值 : 0x12 0x34 0x56 0x78
17 | ```
18 |
19 | - 小端序(Little-endian): 在小端序中,数据的低位字节(最不重要的字节)存储在较低的内存地址中,而数据的高位字节(最重要的字节)存储在较高的内存地址中。换句话说,字节序是从低位到高位。例如,32位整数 `0x12345678` 在小端序中的存储顺序是:
20 |
21 | ```cpp
22 | 内存地址: 0x01 0x02 0x03 0x04
23 | 存储值 : 0x78 0x56 0x34 0x12
24 | ```
25 |
26 | 在处理跨平台数据交换时,了解大端序和小端序是很重要的。为了避免字节序问题,可以使用一种通用的字节序,如网络字节序(大端序),在发送和接收数据时进行字节序转换。
27 |
28 | ### 2. 内存的分配方式有几种?
29 |
30 | **静态内存分配(Static Memory Allocation)**: 静态内存分配是在编译时确定内存大小和位置的分配方式。全局变量、静态变量和常量都使用静态内存分配。这些变量在程序的整个生命周期中都存在,直到程序结束。静态内存分配的优点是速度快,开销小;缺点是分配的内存大小在编译时就确定,不能在运行时改变。
31 |
32 | **栈内存分配(Stack Memory Allocation)**: 栈内存分配是在函数调用期间为局部变量和函数参数分配内存的方式。栈内存分配由编译器自动处理,无需程序员手动管理。栈内存分配速度快,但分配的内存大小受到栈大小的限制。当函数调用结束时,分配的内存会自动释放。
33 |
34 | **堆内存分配(Heap Memory Allocation)**: 堆内存分配是在程序运行期间动态分配和释放内存的方式。C++中,可以使用`new`和`delete`操作符(或`new[]`和`delete[]`操作符)在堆上分配和释放内存。堆内存分配允许在运行时分配可变大小的内存,但分配和释放的速度相对较慢,且需要程序员手动管理内存的生命周期。不正确地管理堆内存可能导致内存泄漏或悬挂指针等问题。
35 |
36 | 总结:在C++中,有三种常见的内存分配方式:静态内存分配、栈内存分配和堆内存分配。静态内存分配和栈内存分配速度快,但内存大小和生命周期在编译时或函数调用期间确定;堆内存分配允许在运行时分配可变大小的内存,但速度较慢,且需要手动管理内存。
37 |
38 |
39 |
40 | ### 3. 局部变量在内存中如何被分配?是否产生符号?
41 |
42 | 局部变量在内存中是通过栈(Stack)进行分配的。当一个函数被调用时,会为该函数创建一个栈帧(Stack Frame)。栈帧中包含了该函数的局部变量、函数参数以及其他与函数调用相关的信息。局部变量在栈上分配内存是由编译器自动处理的,函数调用结束后,分配的内存会自动释放。
43 |
44 | **关于局部变量是否产生符号**
45 |
46 | 局部变量的作用域仅限于其所在的函数,因此在链接阶段不会产生符号。符号表中的符号通常是全局或静态变量、函数等,它们在编译和链接过程中需要被解析和分配内存。
47 |
48 |
49 |
50 | ### 4. C/C++的内存分配,详细说一下栈、堆、静态存储区?堆快还是栈快?
51 |
52 | C/C++的内存分配主要包括以下几个部分:栈(Stack)、堆(Heap)和静态存储区(Static Storage Area)。这些部分的功能和特点如下:
53 |
54 | - **栈(Stack)**: 栈是一种用于存储局部变量和函数调用信息的内存区域。它是一种后进先出(LIFO)的数据结构,每当一个函数被调用时,都会在栈上创建一个栈帧(Stack Frame)。栈帧中包含了局部变量、函数参数以及其他与函数调用相关的信息。函数调用结束后,分配的内存会自动释放。栈的内存分配和释放速度非常快,但由于栈的大小有限,不能用于存储大量或运行时确定大小的数据。
55 | - **堆(Heap)**: 堆是一种用于动态分配内存的内存区域。在C++中,可以使用`new`和`delete`操作符(或`new[]`和`delete[]`操作符)在堆上分配和释放内存。堆内存的分配和释放需要在运行时进行,速度相对较慢,且需要程序员手动管理内存的生命周期。不正确地管理堆内存可能导致内存泄漏或悬挂指针等问题。由于堆的大小远大于栈,可以用于存储大量或运行时确定大小的数据。
56 | - **静态存储区(Static Storage Area)**: 静态存储区是一种用于存储全局变量、静态变量和常量的内存区域。静态存储区的内存分配在编译时就确定,程序的整个生命周期内都存在,直到程序结束。静态存储区的内存分配速度快,但分配的内存大小在编译时就确定,不能在运行时改变。
57 |
58 | **关于堆和栈的速度**
59 |
60 | 栈上的内存分配和释放速度要快于堆。这是因为栈内存分配和释放仅涉及对栈指针的移动,而堆内存分配和释放需要在运行时进行,涉及到内存管理的数据结构操作。此外,堆内存分配可能会导致内存碎片问题,降低内存利用率。
61 |
62 |
63 |
64 | ### 5. 内存的静态分配和动态分配的区别?
65 |
66 | **分配时间**
67 |
68 | - 静态分配:在编译时确定内存的分配。静态变量、全局变量和常量都使用静态分配。此外,函数中的局部变量和函数参数通常使用栈进行分配,这也被视为静态分配,因为栈内存的分配和释放是在函数调用期间自动进行的。
69 | - 动态分配:在程序运行时分配内存。C++中,可以使用`new`和`delete`操作符(或`new[]`和`delete[]`操作符)在堆上进行动态内存分配和释放。
70 |
71 | **生命周期**
72 |
73 | - 静态分配:全局变量、静态变量和常量的生命周期在程序的整个执行期间。局部变量和函数参数的生命周期仅在函数调用期间。
74 | - 动态分配:动态分配的内存的生命周期取决于程序员何时释放它。它可以在程序的任何阶段创建和释放,但需要程序员手动管理内存的生命周期。
75 |
76 | **管理方式**
77 |
78 | - 静态分配:静态分配的内存由编译器自动管理,程序员无需手动进行内存分配和释放。
79 | - 动态分配:动态分配的内存需要程序员手动进行分配和释放。如果不正确地管理动态分配的内存,可能导致内存泄漏或悬挂指针等问题。
80 |
81 | **使用场景**
82 |
83 | - 静态分配:适用于程序运行期间固定大小的内存需求,例如全局变量、静态变量、常量以及局部变量和函数参数。
84 | - 动态分配:适用于程序运行时才能确定大小的内存需求,例如需要根据用户输入或运行时计算结果分配内存的情况。
85 |
86 |
87 |
88 | ### 6. malloc与free实现原理?
89 |
90 | `malloc` 和 `free` 是 C 语言中用于在堆上分配和释放内存的标准库函数。
91 |
92 | **malloc**
93 |
94 | - 内存分配:`malloc` 向操作系统请求内存,根据系统平台和库实现的不同,它可以使用 `brk()` 和 `mmap()` 两种方式来从操作系统请求内存。小于128K用`brk()` 调整数据段的大小,以分配堆内存;大于128K用`mmap()` ,通过内存映射,在进程的虚拟地址空间中分配内存。
95 | - 内存管理:`malloc` 使用一种数据结构(通常是链表或树形结构)来管理已分配和未分配的内存块。当用户请求内存时,`malloc` 首先在内存管理数据结构中查找一个合适大小的空闲内存块。如果找到合适的内存块,`malloc` 会将其从空闲列表中移除并返回给用户。如果没有找到合适的内存块,`malloc` 会向操作系统请求更多的内存。
96 |
97 | **free**
98 |
99 | 当调用 `free` 函数释放一块内存时,`free` 首先会根据之前 `malloc` 存储的元数据获取内存块的大小和位置。然后,`free` 会将这个内存块放回到空闲内存块列表中。
100 |
101 | 为了减少内存碎片,`free` 可能会合并相邻的空闲内存块。例如,如果一个被释放的内存块和它相邻的内存块都是空闲的,`free` 可以将它们合并成一个更大的空闲内存块。
102 |
103 | `malloc` 和 `free` 仅分配和释放内存,而不对内存内容进行初始化。在 C++ 中,`new` 和 `delete` 操作符不仅负责内存分配和释放,还负责对象的构造和析构。
104 |
105 |
106 |
107 | ### 7. new与delete的实现原理?
108 |
109 | `new` 和 `delete` 是 C++ 语言中用于在堆上分配和释放内存的操作符,它们不仅负责内存管理,还负责对象的构造和析构。
110 |
111 | **new**
112 |
113 | 使用 `new` 操作符创建一个对象时,分为两步骤:
114 |
115 | - **operator new**:`new` 首先会调用底层的内存分配函数(例如,`malloc`)来分配所需的内存。这涉及到查找一个合适的空闲内存块并将其从空闲内存块列表中移除。需要注意的是,不同的编译器和平台可能使用不同的内存分配函数。如果分配失败会抛出`bad_alloc`异常
116 | - **placement new**:在分配的内存上调用对象的构造函数,以初始化对象的状态。
117 |
118 | **delete**
119 |
120 | 使用 `delete` 操作符释放一个对象时,会进行以下步骤:
121 |
122 | - 对象析构:`delete` 首先调用对象的析构函数,以释放对象所持有的资源并清理对象的状态。
123 | - 内存释放:接着,`delete` 调用底层的内存释放函数(例如,`free`)将内存归还给操作系统。这涉及到将内存块放回空闲内存块列表,并可能合并相邻的空闲内存块以减少内存碎片。同样,不同的编译器和平台可能使用不同的内存释放函数。
124 |
125 |
126 |
127 | ### 8. delete是如何知道释放内存的大小?
128 |
129 | 与编译器和操作系统的实现有关。通常,编译器和内存管理子系统会在分配的内存块中存储一些元数据,以帮助跟踪内存的分配和释放。
130 |
131 | 当使用 `new` 操作符分配内存时,内存管理子系统会在实际分配的内存块中包含一些额外的信息,例如内存块的大小。这些信息通常存储在分配给对象的内存块之前的位置。当 `delete` 操作符被调用时,它会根据指针检索这些元数据,以确定要释放的内存块的大小。
132 |
133 |
134 |
135 | ### 9. malloc 和 new 有什么区别?
136 |
137 | `malloc` 和 `new` 都用于在堆上分配内存。
138 |
139 | **可以调用构造函数与析构函数**
140 |
141 | **类型安全**
142 |
143 | - `malloc`:返回的指针类型为 `void*`,需要显式类型转换为适当的类型。
144 | - `new`:返回相应类型的指针,提供了类型安全。不需要显式类型转换。
145 |
146 | **内存分配**
147 |
148 | - `malloc`:分配内存时,需要指定所需内存的字节数。它返回一个指向分配内存的指针,或者在无法分配内存时返回 `NULL`。
149 | - `new`:分配内存时,无需指定字节数。它根据所需类型自动计算所需内存的大小,并返回相应类型的指针。如果无法分配内存,它会抛出 `std::bad_alloc` 异常(除非使用 `nothrow` 修饰符)。
150 |
151 |
152 |
153 | ### 10. malloc申请的存储空间能用delete释放吗?
154 |
155 | 使用 `malloc` 申请的存储空间不应使用 `delete` 来释放。同样,使用 `new` 分配的内存也不应使用 `free` 来释放。 `malloc` 和 `free` 是 C 语言的内存管理函数,而 `new` 和 `delete` 是 C++ 的内存管理操作符,内存管理策略不同。
156 |
157 | `new` 和 `delete` 的内存管理除了分配和释放内存外,还涉及到对象的构造和析构。当你使用 `new` 创建对象时,它会在分配内存的同时调用对象的构造函数。而使用 `delete` 释放内存时,它会先调用对象的析构函数,然后释放内存。
158 |
159 | 如果使用 `delete` 来释放通过 `malloc` 分配的内存,可能会导致未定义行为,例如:
160 |
161 | - `delete` 可能尝试调用析构函数,而 `malloc` 分配的内存并没有调用构造函数。这可能导致程序错误,例如访问无效的资源。
162 | - `malloc` 和 `new` 可能使用不同的内存管理策略,导致 `delete` 无法正确释放 `malloc` 分配的内存。
163 |
164 |
165 |
166 | ### 11. malloc、realloc、calloc的区别?
167 |
168 | `malloc`、`realloc` 和 `calloc` 都是 C 语言中的内存分配函数,用于在堆上分配内存。
169 |
170 | **`malloc`**
171 |
172 | - 功能:用于分配指定大小的内存。
173 | - 参数:接受一个参数,即所需内存的字节数。
174 | - 初始化:分配的内存不会被初始化,它包含的数据是未定义的。
175 | - 返回值:成功时返回指向分配内存的指针,失败时返回 `NULL`。
176 |
177 | **`calloc`**
178 |
179 | - 功能:用于分配指定数量的指定大小的内存块。
180 | - 参数:接受两个参数,一个是所需内存块的数量,另一个是每个内存块的字节数。
181 | - 初始化:分配的内存会被初始化为 0。
182 | - 返回值:成功时返回指向分配内存的指针,失败时返回 `NULL`。
183 |
184 | **`realloc`**
185 |
186 | - 功能:用于调整之前分配的内存块的大小。
187 | - 参数:接受两个参数,一个是指向之前分配的内存块的指针,另一个是新的内存大小(字节数)。
188 | - 初始化:如果内存块的大小增加,新增的内存部分不会被初始化,它包含的数据是未定义的。
189 | - 返回值:成功时返回指向新大小的内存的指针,失败时返回 `NULL`。在某些情况下,可能会返回与原始指针相同的值(例如,当内存大小未改变或内存已经足够大时)。如果返回的指针与原始指针不同,原始指针所指向的内存将被释放。
190 |
191 | **总结**
192 |
193 | - `malloc` 是用于分配指定大小的内存,不进行初始化。
194 | - `calloc` 是用于分配指定数量的指定大小的内存块,并将内存初始化为 0。
195 | - `realloc` 是用于调整之前分配的内存块的大小,如果内存增加,新增部分不会被初始化。
196 |
197 |
198 |
199 | ### 12. 被free回收了的内存是否立刻还给操作系统?
200 |
201 | 当使用 `free` 函数回收内存时,这些内存是否立刻还给操作系统取决于实现和操作系统。C 库实现会在内部维护一个内存池,将回收的内存加入内存池以供将来分配。
202 |
203 | 在某些情况下,内存池可能会变得非常大,C 库实现可以选择将部分内存归还给操作系统。归还内存的策略取决于实现和操作系统,例如可能会基于内存使用量、空闲内存块的大小或空闲时间来决定。
204 |
205 | `free` 函数主要目的是将内存归还给内部的内存池,以便在后续的内存分配请求(如 `malloc`、`calloc` 和 `realloc`)中重用。只有在特定条件下,内存才可能被归还给操作系统。
206 |
207 |
208 |
209 | ### 13. 深拷贝与浅拷贝?
210 |
211 | **浅拷贝**: 浅拷贝是对对象的顶层结构进行复制,但不会复制对象内部的子对象或指针所引用的内存。换句话说,浅拷贝创建了一个新对象,这个新对象与原对象共享内部数据结构和引用。这可能会导致在一个对象上的更改影响另一个对象的情况。
212 |
213 | 举例来说,如果你有一个包含指针成员的对象,浅拷贝会复制指针本身,而不是指针所指向的内存。这意味着拷贝后的对象与原对象共享相同的指针指向的内存。
214 |
215 | **深拷贝**: 深拷贝则是对对象的整个结构进行递归复制,包括子对象和指针所引用的内存。深拷贝会创建一个与原对象完全独立的新对象。由于深拷贝创建了原对象的完整副本,对一个对象的更改不会影响另一个对象。
216 |
217 | 以包含指针成员的对象为例,深拷贝会复制指针所指向的内存,然后在新对象中创建一个新的指针指向这块新的内存。这样,拷贝后的对象与原对象在内存上完全独立。
218 |
219 | 浅拷贝通常更快、占用更少内存,但可能导致意外的副作用,例如多个对象共享同一个内部数据结构。深拷贝虽然能够创建独立的对象副本,但可能更慢,占用更多内存。
--------------------------------------------------------------------------------
/src/cpp/rank.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: C++面试题频排序
3 | pageInfo: false
4 | editLink: false
5 | comment: false
6 | sidebar: false
7 | ---
8 |
9 | -------
10 | -------
11 |
12 |
13 |
14 | ### 手写智能指针类?(1次)
15 |
16 | ### 说一下C++多态有几种方式,分别怎么实现?(1次)
17 |
18 | ### 重定义和重载的区别是什么?(1次)
19 |
20 | ### 说一下虚函数?(1次)
21 |
22 | ### C++的内存分为哪几个区,分别是做什么的?(1次)
23 |
24 | ### 堆和栈的区别说一下?(1次)
25 |
26 | ### malloc分配在哪,alloc呢?(1次)
--------------------------------------------------------------------------------
/src/data-structure/rank.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 数据结构面试题频排序
3 | pageInfo: false
4 | editLink: false
5 | sidebar: false
6 | ---
7 |
8 | ------
9 |
10 | ------
11 |
12 | ### BFS和DFS的区别?(1次)
13 |
14 | ### Hash的实现方式?(1次)
15 |
16 | ### 介绍一下红黑树?(1次)
17 |
18 | ### 1w个数取前10大的数,用什么排序算法?(1次)
19 |
20 | ### 堆排序用的是小顶堆和大顶堆?(1次)
21 |
22 |
--------------------------------------------------------------------------------
/src/deliver/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | editLink: false
4 | comment: false
5 | ---
--------------------------------------------------------------------------------
/src/design/README.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | pageInfo: false
4 | title: 设计题
5 | editLink: false
6 | comment: false
7 |
8 | ---
9 |
10 | # [常见设计题](./design.md)
11 |
12 | # [常见设计题](./design.md)
13 |
14 | # [海量数据处理题](./bigdata..mds)
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/design/bigdata.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### 海量日志数据,提取出某日访问百度次数最多的那个IP?
4 |
5 | 首先是找到这一天的日志,并且是访问百度的IP从日志中提取出来逐个写入大文件中,如果IP是32位的,最多可能有2^32次方种结果。
6 |
7 | 采用映射的方法,比如%1000,把大文件依次映射成1000个小文件,找出每个小文件中出现频率最多的IP,可以使用hashMap统计频率,依次找出每个文件中出现频率最大IP,一共1000个。然后在1000个IP中找出频率最大即为所求,可以使用归并或者小顶堆。
8 |
9 |
10 |
11 | ### 寻找热门查询中,1000万个查询字符串中最热门的10个查询?要求内存使用不超过1G,每个查询串长度都是1~255字节?
12 |
13 | 1000万个字符串肯定会有重复,假设不重复字段大约300万,3M * 1K/4 = 0.75G,可以在内存中全部装下,因此采用hashTable,key位字符串,value位为出现的次数,每次读取一个串,如果串在hashTable中就将统计频率加1,否则将value置为1。然后维护一个堆,保存10个元素,找出TopK,遍历300个串的value分别与根元素进行比较,最终时间复杂度为O(N)+M*O(logK),N为1000万,M为300万,K为堆大小10。
14 |
15 |
16 |
17 | ### 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词?
18 |
19 | 顺序读取文件,对于每个词采用hash%5000,映射到(x0,x1,……,x4999),每个文件大约200KB,如果有文件大小超过1K就继续分治,直到所有文件大小都小于1M。对于每个小文件采用hashMap或者前缀树统计相应的词和频率。取出现频率最大的100个词,存入文件可以得到5000个文件,最后把5000个文件进行归并排序。
20 |
21 |
22 |
23 | ### 海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10?
24 |
25 | 如果每个元素只出现一次并且出现在某一台机器上,可以在每台电脑上求TOP10,采用最大堆,然后求出每个电脑的TOP10之后将100个电脑的TOP组合起来得到1000条数据,再用大顶堆划分出TOP10。
26 |
27 | 如果同一元素重复出现在不同电脑中,可以遍历一遍所数据后hash取模,使同一元素只出现在一台电脑上。统计每个元素的TOP10,找出最后的TOP10。
28 |
29 | 或者直接暴力统计每个电脑各个元素出现的次数,把同一元素在不同电脑上次数相加,找出最终数据的TOP10。
30 |
31 |
32 |
33 | ### 有10个文件,每个文件1G,每个文件的每一行存放的都是用户的查询,每个文件的查询都可能重复。要求你按照查询的频度排序?
34 |
35 | 顺序读取10个文件,按照hash(query)%10的结果写入10个文件中,生成的新文件大小也是1G。找一个内存是2G的机器,依次对用hashMap(query, query_count)来统计每个query出现的次数。然后将排序好的query和count存储到文件中,得到10个已经排序的文件,最后对10个文件进行归并排序。
36 |
37 |
38 |
39 | ### 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
40 |
41 | 50亿个URL每个URL是64字节,一共占用320亿字节,内存4G装不下,所以采用分治的思想。先遍历a文件,对于每个hash(URL)%1000,分别将1000个URL存储到1000个小文件里面,记为a1、a2、……、a1000,每个文件大约就是300M,遍历文件b采取同样的方法。因为使用的是相同的哈希算法,所以相同的URL在对应文件对里面,这样就会有1000对小文件。不对应的小文件不可能有相同的URL。
42 |
43 | 然后对每对URL,先把一个文件的URL存储到hashSet中,遍历另一个小文件的每个URL,看是否在hashSet,如果有相同的URL存储到文件就行。
44 |
45 | 如果允许一定错误率,可以使用布隆过滤器,4亿内存可以保存340亿bit。用一个布隆过滤器映射340亿bit,然后读取另一个文件的URL,检查是否在布隆过滤器里面,快速判断URL是否存在。
46 |
47 |
48 |
49 | ### 在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数?
50 |
51 | **方案1**:采用2比特位的位图,每个数分配2位,00表示这个数不存在,01表示出现一次,10表示出现多次,11无意义,共需要内存2^32*2 = 1G内存,扫描2.5亿个整数判断位图中是否存在,并调换对应的位,查看所有的01位并进行输出即可。
52 |
53 | **方案2**:先把2.5亿个小文件进行划分,在小文件中找到不重复整数,并且排序,然后再归并。
54 |
55 |
56 |
57 | ### 给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?
58 |
59 | 采用位图,申请512M内存,一位代表一个unsigned int,然后读入40亿数字,设置相应的bit位。读出要查询的数并且判段bit是否为1。
60 |
61 |
62 |
63 | ### 100w个数中找出最大的100个数?
64 |
65 | **局部淘汰法**:选取前100个元素,并排。依次扫描剩余元素,与排好序的最小的元素比,如果比这个最小的大,那么把这个最小的元素删除,并利用插入排序的思想,把新元素插入到序列中。依次循环,直到扫描了所有的元素。复杂度为O(100w\*100)。
66 | **快排**:采用快速排序的思想,每次分割之后只考虑比轴大的一部分,知道比轴大的一部分在比100多的时候,采用传统排序算法排序,取前100个。复杂度为O(100w\*100)。
67 | **最小堆**:用一个含100个元素的最小堆完成。复杂度为O(100w*lg100)。
68 |
69 | **双层桶划分**:整数个数一共2\^32个,划分为2\^8个区域,一个单一的文件可以代表一个区域。将数据离散到不同区域,在不同的区域利用bitmap进行统计,只要磁盘空间足够即可。
70 |
71 |
72 |
73 | ### 5亿个int找到它的中位数?
74 |
75 | **bitmap**:可以把int划分为2\^16个区域,然后读取数据落在各个区域的个数,在统计结构中判断中位数落在哪个位置,同时对这个区域操作,知道第几大的是中位数。数据量过大可以进行两次划分,先将int64放入2\^24个区域内,确定是第几区域大的数,将该区域划分为2^20个子区域,确定是子区域第几大的数字,直接进行统计。
76 |
77 | **快排**:内存足够的情况可以使⽤用类似quick sort的思想进行,均摊复杂度为O(n):随机选取一个元素,将比它小的元素放在它左边,比它大的元素放在右边;如果它恰好在中位数的位置,那么它就是中位数,可以直接返回;如果小于它的数超过一半,那么中位数一定在左半边,递归到左边处理;否则中位数一定在右半边,根据左半边的元素个数计算出中位数是右半边的第几大,然后递归到右半边处理。
78 |
79 |
--------------------------------------------------------------------------------
/src/design/rank.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 设计题和智力题题频排序
3 | pageInfo: false
4 | editLink: false
5 | comment: false
6 | sidebar: false
7 | ---
8 |
9 | ------
10 |
11 | ------
12 |
13 |
14 |
15 | ### 设计一个秒杀系统?(1次)
16 |
17 | ### 如果给你一个分布式系统,要求你限流,你怎么做,如何优化?(1次)
18 |
19 | ### 实际开发如何避免死锁?(1次)
20 |
21 | ### 后端解决同一个订单重复提交?(1次)
22 |
23 | ### 10亿个整数找出不同的整数,限制1G内存?(1次)
24 |
25 | ### 300个数据初始化后如何判重、如果是三千万个整型数据呢?(1次)
26 |
27 |
--------------------------------------------------------------------------------
/src/development-log/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | editLink: false
4 | title: 开发日志
5 | comment: false
6 | sidebar: heading
7 | ---
8 |
9 |
10 |
11 | ## 2023年4月11日
12 |
13 | - 题频界面更新两篇面经
14 | - 重写3道设计题(未推送)
15 | - 新增3道智力题(未推送)
16 |
17 | ## 2023年4月10日
18 |
19 | - 操作系统界面重构完成
20 |
21 | ## 2023年4月8日
22 |
23 | - 题频界面更新两篇面经
24 | - 算法界面更新6道题(未推送)
25 | - 操作系统更新7道题(未推送)
26 |
27 | ## 2023年4月7日
28 |
29 | - 题频界面更新两篇面经
30 | - 算法界面更新8道字符串的题(未推送)
31 | - 操作系统更新10道题(未推送)
32 |
33 | ## 2023年4月5日
34 |
35 | - 题频界面更新两篇面经
36 | - 算法界面更新10道树的题(未推送)
37 | - 操作系统更新10道题(未推送)
38 |
39 | ## 2023年4月3日
40 |
41 | - 更新归并排序、桶排序、快速排序思路和示例代码
42 |
43 | ## 2023年4月2日
44 |
45 | - C++更新150余道题目
46 | - 链表更新20余道题目,树更新10道题目
47 |
48 | ## 2023年3月16日
49 |
50 | - 题频界面更新四篇面经
51 | - 引入Spring界面
52 | - 算法界面加入SEO优化
53 |
54 | ## 2023年2月26日
55 |
56 | - 算法界面修改3处错误
57 | - 引入C++界面
58 | - 操作系统界面更新10道题目
59 | - 设计题界面修复若干错误
60 |
61 | ## 2023年2月25日
62 |
63 | - 题频界面引入三篇面经内容
64 | - 算法更新20道Java题解
65 |
66 | ## 2023年2月24日
67 |
68 | - 完成公众号介绍文章和打赏界面文章
69 | - 题频界面引入四篇面经内容
70 | - Java界面图片导入
71 |
72 | ## 2023年2月23日
73 |
74 | - 定义[首页]六大模块
75 | - 主页引入公众号图片
76 | - 打赏页引入图片
77 | - 重新构建指南页面
78 | - 定义题频页面
79 |
80 | ## 2023年2月22日
81 |
82 | - github上传源代码,开源项目
83 | - golang更新面试题
84 | - 主页布局重新更新,导航栏和侧边栏重新定义
85 | - 域名审核通过,使用新域名 csview.cn
86 | - 解决vue编译过程中内存溢出问题
87 | - 算法更新Java题解35道
88 |
89 | ## 2023年2月21日
90 |
91 | - 算法更新33道Java题解
92 | - golang更新部分习题
93 | - 主题组件升级,配置search插件
94 |
95 |
96 |
97 | ## 2023年2月20日
98 |
99 | - Java界面基础知识分享
100 | - 算法更新20道Java题解
101 | - [学习路线]文章完成50%
102 |
103 |
104 |
105 | ## 2023年2月19日
106 |
107 | - Java语言知识重新分类
108 | - [学习路线]文章完成30%
109 | - 修复设计题部分错误
110 |
111 |
112 |
113 | ## 2023年2月18日
114 |
115 | - 修复页面跳转索引无效bug
116 | - golang页面新增8题
117 | - 操作系统页面整理重新分类
118 | - 算法题重新筛选
119 | - MySQL更新1题
120 | - 设计题重新分类
121 | - 尝试引入侧边栏图片
122 |
123 |
124 |
125 | ## 2023年2月17日
126 |
127 | - 为页面分别配置评论和文章信息内容
128 | - 计算机网络、数据库、操作系统、golang修改更新30余道题目
129 | - RabbitMQ页面更新和配置
130 | - HR常见面试题页面引入
131 | - K8s页面修改
132 | - 智力题、设计题审核更新
133 | - 逐步为内容增加参考来源
134 |
135 |
136 |
137 | ## 2023年2月16日
138 |
139 | - 配置Waline并开启评论功能
140 | - [面试内容]文章更新
141 | - 清除所有无效页面链接
142 | - 算法题目整理
143 | - 智力题、设计题、RabbitMQ页面引入内容
144 |
145 |
146 |
147 | ## 2023年2月15日
148 |
149 | - 完成Redis内容页面更新
150 | - 所有页面信息和标注优化:非内容页面去除编辑和作者信息按钮
151 | - 每个模块题目数据统计
152 | - 计算机网络、golang、MySQL增加问题重要程度标注
153 | - csview域名提交腾讯云审核
154 |
155 |
156 |
157 | ## 2023年2月14日
158 |
159 | - 完成**项目介绍**页面
160 | - 所有页面内容按照章节分割
161 | - 重现构建导航栏和索引
162 |
163 |
164 |
165 | ## 2023年2月13日
166 |
167 | - 再次尝试docSearch插件配置(**失败**)
168 | - 页面引入badge,标识问题重要程度
169 | - Redis页面内容更新,进度完成50%
170 | - **项目介绍**更新,进度完成30%
171 | - 算法题目更新
172 |
173 |
174 |
175 | ## 2023年2月12日
176 |
177 | - 重新命名网站为CSView
178 | - 申请域名csview.cn(等待审核更新)
179 | - 页面重新定义布局规则:分类设为二级标题,问题设为三级标题,尽量减少四级小标题使用
180 | - 计算机网络、数据库、golang问题回答优化
181 |
182 |
183 |
184 | ## 2023年2月11日
185 |
186 | - 算法页面引入代码切换容器
187 | - 计算机网络、数据库、golang页面优化:增加问题和优化回答
188 | - 算法页面修改样式
189 | - 导航栏引入全局搜索插件,使用search-Pro
190 | - 使用algolia网站配置docSearch爬虫,构建全文搜索功能(**失败**)
191 | - [开始学习]侧边栏引入
192 | - 更新白天和夜间的代码块样式
193 |
194 | ## 2023年2月10日
195 |
196 | - 项目提交github并部署托管到vercel
197 | - 使用vercel解析关联域名csguide.xyz
198 | - 网站页面取消面包屑导航
199 | - 算法页面样式重新设计布局
200 | - 修复c++代码块不显示样式问题
201 | - 白天夜间网站采用不同logo
202 | - 计算机网络界面内容修改完善
203 | - 网站全文搜索docSearch申请
204 |
205 | ## 2023年2月9日
206 |
207 | - csguide.xyz域名审核通过
208 | - SSL证书申请
209 | - 使用vuepress-theme-hope重新初始化网站
210 | - 网站基本结构设计
211 | - 完成顶部导航栏和侧边栏配置
212 | - 导航栏引入图标
213 | - golang、数据库、计算机网络页面内容更新
214 | - 夜间模式网页首页logo适配
215 | - 搜索插件和网页浏览次数插件引入
216 | - 首页[开始学习]按钮配置
217 | - 容器使用引入
--------------------------------------------------------------------------------
/src/docker/rank.md:
--------------------------------------------------------------------------------
1 | ### 容器相比于虚拟机有什么优势?(1次)
2 |
3 | ### docker-compose的编排结构?(1次)
4 |
5 | ### 有写过dockerfile吗?RUN和CMD命令有什么区别?(1次)
--------------------------------------------------------------------------------
/src/golang/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | title: golang
4 | editLink: false
5 | comment: false
6 | ---
7 |
8 | # [概述](./summary.md)
9 |
10 | # [概述](./summary.md)
11 |
12 | # [关键字](./keyword.md)
13 |
14 | # [GMP](./gmp.md)
15 |
16 | # [垃圾回收](./gc.md)
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/golang/gc.md:
--------------------------------------------------------------------------------
1 | ### golang的垃圾回收?
2 |
3 | golang GC 算法使用的是无分代(对象没有代际之分)、不整理(回收过程中不对对象进行移动与整理)、并发(与用户代码并发执行)的三色标记清扫算法。
4 |
5 |
6 |
7 | 三色标记法将对象分为三类,并用不同的颜色相称:
8 |
9 | - **白色对象(可能死亡)**:未被回收器访问到的对象。在回收开始阶段,所有对象均为白色,当回收结束后,白色对象均不可达
10 | - **灰色对象(波面)**:已被回收器访问到的对象,但回收器需要对其中的一个或多个指针进行扫描,因为他们可能还指向白色对象
11 | - **黑色对象(确定存活)**:已被回收器访问到的对象,其中所有字段都已被扫描,黑色对象中任何一个指针都不可能直接指向白色对象
12 |
13 | 标记过程如下:
14 |
15 | - 第一步:起初所有的对象都是白色的
16 | - 第二步:从根对象出发扫描所有可达对象,标记为灰色,放入待处理队列
17 | - 第三步:从待处理队列中取出灰色对象,将其引用的对象标记为灰色并放入待处理队列中,自身标记为黑色
18 | - 重复第三步,直到待处理队列为空,此时白色对象即为不可达的“垃圾”,回收白色对象
19 |
20 |
21 |
22 | ### 写屏障?
23 |
24 | 当标记和程序是并发执行的,这就会造成一个问题。在标记过程中,有新的引用产生,可能会导致误清扫。清扫开始前,标记为黑色的对象引用了一个新申请的对象,它肯定是白色的,而黑色对象不会被再次扫描,那么这个白色对象无法被扫描变成灰色、黑色,它就会最终被清扫。golang 采用了写屏障,作用就是为了避免这类误清扫问题,写屏障即在内存写操作前,维护一个约束,从而确保清扫开始前,黑色的对象不能引用白色对象。gc一旦开始,无论是创建对象还是对象的引用改变,都会先变为灰色。
25 |
26 |
27 |
28 | ### 垃圾回收的触发条件?
29 |
30 | - 系统触发:运行时自行根据内置的条件,检查、发现到则进行 GC 处理,维护整个应用程序的可用性
31 | - 系统监控:当超过两分钟没有产生任何GC时,强制触发 GC
32 | - 步调(Pacing)算法,其核心思想是控制内存增长的比例,当前内存分配达到一定比例则触发
33 | - 触发:开发者在业务代码中自行调用 runtime.GC 方法来触发 GC
--------------------------------------------------------------------------------
/src/golang/gmp.md:
--------------------------------------------------------------------------------
1 | ### GMP模型?
2 |
3 | G(goroutine)
4 |
5 | go 语言中的协程 goroutine 的缩写,相当于操作系统中的进程控制块。其中存着 goroutine 的运行时栈信息,CPU 的一些寄存器的值以及执行的函数指令等。sched字段保存了 goroutine 的上下文。goroutine 切换的时候不同于线程有 OS 来负责这部分数据,而是由一个 gobuf 结构体来保存。
6 |
7 | ```go
8 | type g struct {
9 | stack stack // 描述真实的栈内存,包括上下界
10 |
11 | m *m // 当前的 m
12 | sched gobuf // goroutine 切换时,用于保存 g 的上下文
13 | param unsafe.Pointer // 用于传递参数,睡眠时其他 goroutine 可以设置 param,唤醒时该goroutine可以获取
14 | atomicstatus uint32
15 | stackLock uint32
16 | goid int64 // goroutine 的 ID
17 | waitsince int64 // g 被阻塞的大体时间
18 | lockedm *m // G 被锁定只在这个 m 上运行
19 | }
20 |
21 | ```
22 |
23 | gobuf 保存了当前的栈指针,计数器,还有 g 自身,这里记录自身 g 的指针的目的是为了**能快速的访问到 goroutine 中的信息**。gobuf 的结构如下:
24 |
25 | ```go
26 | type gobuf struct {
27 | sp uintptr
28 | pc uintptr
29 | g guintptr
30 | ctxt unsafe.Pointer
31 | ret sys.Uintreg
32 | lr uintptr
33 | bp uintptr // for goEXPERIMENT=framepointer
34 | }
35 | ```
36 |
37 | M(Machine)
38 |
39 | M代表一个操作系统的主线程,对内核级线程的封装,数量对应真实的 CPU 数。一个 M 直接关联一个 os 内核线程,用于执行 G。M 会优先从关联的 P 的本地队列中直接获取待执行的 G。M 保存了 M 自身使用的栈信息、当前正在 M上执行的 G 信息、与之绑定的 P 信息。
40 |
41 | 结构体 M 中,curg代表结构体M当前绑定的结构体 G ;g0 是带有调度栈的 goroutine,普通的 goroutine 的栈是在**堆上**分配的可增长的栈,但是 g0 的栈是 **M 对应的线程**的栈。与调度相关的代码,会先切换到该 goroutine 的栈中再执行。
42 |
43 | ```go
44 | type m struct {
45 | g0 *g // 带有调度栈的goroutine
46 |
47 | gsignal *g // 处理信号的goroutine
48 | tls [6]uintptr // thread-local storage
49 | mstartfn func()
50 | curg *g // 当前运行的goroutine
51 | caughtsig guintptr
52 | p puintptr // 关联p和执行的go代码
53 | nextp puintptr
54 | id int32
55 | mallocing int32 // 状态
56 |
57 | spinning bool // m是否out of work
58 | blocked bool // m是否被阻塞
59 | inwb bool // m是否在执行写屏蔽
60 |
61 | printlock int8
62 | incgo bool
63 | fastrand uint32
64 | ncgocall uint64 // cgo调用的总数
65 | ncgo int32 // 当前cgo调用的数目
66 | park note
67 | alllink *m // 用于链接allm
68 | schedlink muintptr
69 | mcache *mcache // 当前m的内存缓存
70 | lockedg *g // 锁定g在当前m上执行,而不会切换到其他m
71 | createstack [32]uintptr // thread创建的栈
72 | }
73 | ```
74 |
75 | P(Processor)
76 |
77 | Processor 代表了 M 所需的上下文环境,代表 M 运行 G 所需要的资源。是处理用户级代码逻辑的处理器,可以将其看作一个局部调度器使 go 代码在一个线程上跑。当 P 有任务时,就需要创建或者唤醒一个系统线程来执行它队列里的任务,所以 P 和 M 是相互绑定的。P 可以根据实际情况开启协程去工作,它包含了运行 goroutine 的资源,如果线程想运行 goroutine,必须先获取 P,P 中还包含了可运行的 G 队列。
78 |
79 | ```go
80 | type p struct {
81 | lock mutex
82 |
83 | id int32
84 | status uint32 // 状态,可以为pidle/prunning/...
85 | link puintptr
86 | schedtick uint32 // 每调度一次加1
87 | syscalltick uint32 // 每一次系统调用加1
88 | sysmontick sysmontick
89 | m muintptr // 回链到关联的m
90 | mcache *mcache
91 | racectx uintptr
92 |
93 | goidcache uint64 // goroutine的ID的缓存
94 | goidcacheend uint64
95 |
96 | // 可运行的goroutine的队列
97 | runqhead uint32
98 | runqtail uint32
99 | runq [256]guintptr
100 |
101 | runnext guintptr // 下一个运行的g
102 |
103 | sudogcache []*sudog
104 | sudogbuf [128]*sudog
105 |
106 | palloc persistentAlloc // per-P to avoid mutex
107 |
108 | pad [sys.CacheLineSize]byte
109 | }
110 | ```
111 |
112 |
113 |
114 | ### GMP的调度流程?
115 |
116 | 
117 |
118 | - 每个 P 有个局部队列,局部队列保存待执行的goroutine(流程 2),当 M 绑定的 P 的的局部队列已经满了之后就会把 goroutine 放到全局队列(流 程 2-1)
119 | - 每个 P 和一个 M 绑定,M 是真正的执行 P 中 goroutine 的实体(流程 3), M 从绑定的 P 中的局部队列获取 G 来执行
120 | - 当 M 绑定的 P 的局部队列为空时,M 会从全局队列获取到本地队列来执行 G (流程 3.1),当从全局队列中没有获取到可执行的 G 时候,M 会从其他 P 的局部队列中偷取 G 来执行(流程 3.2),这种从其他 P 偷的方式称为 work stealing
121 | - 当 G 因系统调用(syscall)阻塞时会阻塞 M,此时 P 会和 M 解绑即 hand off,并寻找新的 idle 的 M,若没有 idle 的 M 就会新建一个 M(流程 5.1)
122 | - 当 G 因 channel 或者 network I/O 阻塞时,不会阻塞 M,M 会寻找其他 runnable 的 G;当阻塞的 G 恢复后会重新进入 runnable 进入 P 队列等待执 行(流程 5.3)
123 |
124 |
125 |
126 | ### P和M的个数?
127 |
128 | - P: 由启动时环境变量 `$GOMAXPROCS` 或者是由 `runtime`的方法`GOMAXPROCS()`决定。这意味着在程序执行的任意时刻都只有`$GOMAXPROCS`个goroutine在同时运行。
129 | - M:
130 | - Go 语言本身的限制:Go 程序启动时,会设置 M 的最大数量,默认 10000,但是内核很难支持这么多的线程数,所以这个限制可以忽略。
131 | - runtime/debug 中的 SetMaxThreads 函数,设置 M 的最大数量。
132 | - 一个 M 阻塞了,会创建新的 M。
133 |
134 | M 与 P 的数量没有绝对关系,一个 M 阻塞,P 就会去创建或者切换另一个 M,所以,即使 P 的默认数量是 1,也有可能会创建很多个 M 出来。
135 |
136 |
137 |
138 | ### **P和M何时会被创建**?
139 |
140 | P: 在确定了 P 的最大数量 n 后,运行时系统会根据这个数量创建 n 个 P。
141 |
142 | M: 没有足够的 M 来关联 P 并运行其中的可运行的 G 时创建。比如所有的 M 此时都阻塞住了,而 P 中还有很多就绪任务,就会去寻找空闲的 M,而没有空闲的,就会去创建新的 M。
143 |
144 |
145 |
146 | ### goroutine创建流程?
147 |
148 | 在调用go func()的时候,会调用runtime.newproc来创建一个goroutine,这个goroutine会新建一个自己的栈空间,同时在G的sched中维护栈地址与程序计数器这些信息(备注:这些数据在goroutine被调度的时候会被用到。准确的说该goroutine在放弃cpu之后,下一次在重新获取cpu的时候,这些信息会被重新加载到cpu的寄存器中。)
149 |
150 | 创建好的这个goroutine会被放到它所对应的内核线程M所使用的上下文P中的run_queue中,等待调度器来决定何时取出该goroutine并执行,通常调度是按时间顺序被调度的,这个队列是一个先进先出的队列。
151 |
152 |
153 |
154 | ### goroutine什么时候会被挂起?
155 |
156 | - waitReasonChanReceiveNilChan:对未初始化的 channel 进行读操作
157 | - waitReasonChanSendNilChan:对未初始化的 channel 进行写操作
158 | - 在 main goroutine 发生 panic 时,会触发
159 | - 在调用关键字 select 时会触发
160 | - 在调用关键字 select 时,若一个 case 都没有,会直接触发
161 | - 在 channel 进行读操作,会触发
162 | - 在 channel 进行写操作,会触发
163 | - sleep 行为,会触发
164 | - IO 阻塞等待时,例如:网络请求等
165 | - 在垃圾回收时,主要场景是 GC 标记终止和标记阶段时触发
166 | - GC 清扫阶段中的结束行为,会触发
167 | - 信号量处理结束时,会触发
168 |
169 |
170 |
171 | ### 同时启动了一万个goroutine,会如何调度?
172 |
173 | 一万个G会按照P的设定个数,尽量平均地分配到每个P的本地队列中。如果所有本地队列都满了,那么剩余的G则会分配到GMP的全局队列上。接下来便开始执行GMP模型的调度策略:
174 |
175 | - **本地队列轮转**:每个P维护着一个包含G的队列,不考虑G进入系统调用或IO操作的情况下,P周期性的将G调度到M中执行,执行一小段时间,将上下文保存下来,然后将G放到队列尾部,然后从队首中重新取出一个G进行调度。
176 | - **系统调用**:P的个数默认等于CPU核数,每个M必须持有一个P才可以执行G,一般情况下M的个数会略大于P的个数,这多出来的M将会在G产生系统调用时发挥作用。当该G即将进入系统调用时,对应的M由于陷入系统调用而进被阻塞,将释放P,进而某个空闲的M1获取P,继续执行P队列中剩下的G。
177 | - **工作量窃取**:多个P中维护的G队列有可能是不均衡的,当某个P已经将G全部执行完,然后去查询全局队列,全局队列中也没有新的G,而另一个M中队列中还有3很多G待运行。此时,空闲的P会将其他P中的G偷取一部分过来,一般每次偷取一半。
178 |
179 |
180 |
181 | ### goroutine内存泄漏和处理?
182 |
183 | **原因**:
184 |
185 | Goroutine 是轻量级线程,需要维护执行用户代码的上下文信息。在运行过程中也需要消耗一定的内存来保存这类信息,而这些内存在目前版本的 Go 中是不会被释放的。因此,如果一个程序持续不断地产生新的 goroutine、且不结束已经创建的 goroutine 并复用这部分内存,就会造成内存泄漏的现象。造成泄露的大多数原因有以下三种:
186 |
187 | - Goroutine 内正在进行 channel/mutex 等读写操作,但由于逻辑问题,某些情况下会被一直阻塞。
188 | - Goroutine 内的业务逻辑进入死循环,资源一直无法释放。
189 | - Goroutine 内的业务逻辑进入长时间等待,有不断新增的 Goroutine 进入等待。
190 |
191 | **解决方法**:
192 |
193 | - 使用channel
194 |
195 | - 1、使用channel接收业务完成的通知
196 |
197 | - 2、业务执行阻塞超过设定的超时时间,就会触发超时退出
198 |
199 | - 使用pprof排查
200 | - pprof是由 Go 官方提供的可用于收集程序运行时报告的工具,其中包含 CPU、内存等信息。当然,也可以获取运行时 goroutine 堆栈信息。
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/src/golang/rank.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: golang面试题频排序
3 | pageInfo: false
4 | editLink: false
5 | comment: false
6 | sidebar: false
7 | ---
8 |
9 | ------
10 |
11 | ------
12 |
13 |
14 | ### 介绍一下goroutine调度机制? (2次)
15 |
16 | ### 介绍一下golang的垃圾回收? (2次)
17 |
18 | ### Slice的底层实现? (2次)
19 |
20 | ### 黑色对象新产生的对象怎么回收? (1次)
21 |
22 | ### GMP中M的时是操作系统内核吗? (1次)
23 |
24 | ### GMP中M的数量是多少? (1次)
25 |
26 | ### 并发编程的channel和sync有什么区别? (1次)
27 |
28 | ### sync底层实现原理? (1次)
29 |
30 | ### String的底层实现?(1次)
31 |
32 | ### String或者切片作为函数参数形参会不会影响实参?(1次)
33 |
34 | ### Slice和数组的区别? (1次)
35 |
36 | ### Slice的扩容机制? (1次)
37 |
38 | ### defer的概述? (1次)
39 |
40 | ### defer的底层原理? (1次)
41 |
42 | ### defer函数和return的执行顺序? (1次)
43 |
44 | ### 有缓冲channel和无缓冲channel有什么区别? (1次)
45 |
46 | ### 读写已关闭的channel会发生什么? (1次)
47 |
48 | ### goroutine与进程、线程的区别?(1次)
49 |
50 | ### make和new的区别?(1次)
51 |
52 | ### map并发安全的吗?如何实现并发安全的map?(1次)
53 |
--------------------------------------------------------------------------------
/src/golang/summary.md:
--------------------------------------------------------------------------------
1 | ### 进程、线程、协程的区别?
2 |
3 | **进程**:进程是每一次程序动态执行的过程,是程序运行的基本单位。进程占据独立的内存,有内存地址,有自己的堆,上级挂靠操作系统,操作系统以进程为单位分配资源(如CPU时间片、内存等),进程是资源分配的最小单位。
4 |
5 | **线程**:线程又叫做轻量级进程,是CPU调度的最小单元。线程从属于进程,是程序的实际执行者,一个进程至少包含一个主线程,也可以有多个子线程。线程会共享所属进程的资源,同时线程也有自己的独占资源。线程切换和线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
6 |
7 | **协程**:协程是一种用户态的轻量级线程,协程的调度完全由用户控制。一个线程可以有多个协程,协程不是被操作系统内核所管理,而是由程序所控制。
8 |
9 | **区别**
10 |
11 | - **拥有资源**:进程是拥有资源的最小单位,线程不拥有资源,但是可以访问隶属进程的资源。进程所维护的是程序所包含的资源静态资源), 如:**地址空间,打开的文件句柄集,文件系统状态,信号处理handler等**;线程所维护的运行相关的资源(动态资源),如:**运行栈,调度相关的控制信息,待处理的信号集等**。
12 | - **并发性**:不仅进程可以并发执行,同一进程的多个线程也可以并发执行。
13 |
14 | - **系统开销**:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。但是进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个进程死掉就等于所有的线程死掉,所以**多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些**。
15 | - **协程和线程**:协程避免了无意义的调度,由此可以提高性能,但是用户调度过程中可能存在风险。
16 |
17 |
18 |
19 | ### goroutine相比线程的优势?
20 |
21 | 协程拥有极高的执行效率,子程序切换不是线程切换而是由程序自身控制,所以没有线程切换的开销。和多线程比,线程的数量越多,协程的性能优势就越明显。
22 |
23 | 协程不需要多线程的锁机制,因为只有一个线程,所以不存在同时写变量的冲突。在协程中控制共享资源不加锁,只需要判断状态就可以,执行效率比多线程要高。
24 |
25 |
26 |
27 | ### go与Java的区别?
28 |
29 | **运行**:go是静态编译语言;Java基于类的面向对象语言,Java应用程序在JVM上运行。
30 |
31 | **函数重载**:go上不允许函数重载,必须具有方法和函数的唯一名称;java允许函数重载。
32 |
33 | **多态**:Java默认允许多态,而go没有。
34 |
35 | **路由配置**:go语言使用HTTP协议进行路由配置;java使用Akka.routing进行路由配置。
36 |
37 | **继承**:go的继承通过匿名组合完成,基类以Struct的方式定义,子类只需要把基类作为成员放在子类的定义中,支持多继承;Java的继承通过extends关键字完成,不支持多继承。
38 |
39 |
40 |
41 | ### go语言中是如何实现继承的?
42 |
43 | 在go中没有extends关键字,所以go并没有原生级别的继承支持。本质上,Go使用组合来代替继承:
44 |
45 | ```go
46 | type Person struct {
47 | Name string
48 | Age int
49 | }
50 |
51 | type Student struct {
52 | Person
53 | School string
54 | }
55 | ```
56 |
57 |
58 |
59 | ### for遍历多次执行goroutine会存在什么问题?
60 |
61 | **在协程中打印for的下标i或当前下标的元素**
62 |
63 | 会随机打印载体中的元素。
64 |
65 | golang值拷贝传递,for循环很快就执行完了,但是创建的10个协程需要做初始化:上下文准备,堆栈,和内核态的线程映射关系的工作,是需要时间的,比for慢,等都准备好了的时候,会同时访问i。这个时候的i肯定是for执行完成后的下标(也可能有个别的协程已经准备好了,取i的时候,正好是5,或者7,就输出了这些数字)。
66 |
67 | 解决的方法就是闭包,给匿名函数增加入参,因为是值传递,所以每次for创建一个协程的时候,会拷贝一份i传到这个协程里面去,或者在开启协程之前声明一个新的变量 = i。
68 |
69 | **for并发读取文件**
70 |
71 | 程序会panic:too many open files
72 |
73 | 解决的方法:通过带缓冲的channel和sync.waitgroup控制协程并发量。
74 |
75 |
76 |
77 | ### init函数是什么时候执行的?
78 |
79 | **特点**:
80 |
81 | - init函数先于main函数自动执行,不能被其他函数调用。
82 | - init函数没有输入参数、返回值。
83 | - 每个包可以有多个init函数,包的每个源文件也可以有多个init函数。
84 | - go没有明确定义同一个包的init执行顺序,编程时程序不能依赖这个执行顺序。
85 | - 不同包的init函数按照包导入的依赖关系决定执行顺序。
86 |
87 | **作用**:
88 |
89 | - 初始化不能采用初始化表达式初始化的变量。
90 | - 程序运行前的注册。
91 | - 实现sync.Once功能。
92 |
93 | **执行顺序**:
94 |
95 | go程序初始化先于main函数执行,由runtime进行初始化,初始化顺序如下:
96 |
97 | - 初始化导入的包,包的初始化顺序并不是按导入顺序执行的,runtime需要解析包依赖关系,没有依赖的包最先初始化
98 | - 初始化包作用域的变量,runtime解析变量依赖关系,没有依赖的变量最先初始化
99 | - 执行包的init函数
100 |
101 | **最终初始化顺序:变量初始化 -> init() -> main()**
102 |
103 |
--------------------------------------------------------------------------------
/src/group/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | editLink: false
4 | comment: false
5 | ---
6 |
7 | 📣扫描下方二维码,即可关注微信公众号CSView:
8 |
9 | 
10 |
11 | 📥点击加入群聊,获取CSView学习交流群二维码,群内不仅有备战招聘面试的朋友,也有已经上岸的同学:
12 |
13 | 
14 |
15 | 📲回复[**面试学习资料**],即可获得本站所有推荐学习资料PDF版本:
16 |
17 |
18 | 
19 |
20 | 📂更多面经解析和面试知识将在公众号更新。
--------------------------------------------------------------------------------
/src/guide/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar: heading
3 | pageInfo: false
4 | editLink: false
5 | comment: false
6 | ---
7 |
8 | ### 📱题频标注
9 |
10 | 本站多数题目用已用标注出现频率:
11 |
12 | - 对于题目,面试必问,如果简历上写了相关内容一定要会
13 |
14 | - 对于题目,面试中出现几率较高,应当作为掌握内容
15 |
16 | - 对于题目,面试偶尔会出现,可作为补充学习或深入探究掌握
17 |
18 |
19 |
20 | ### ➡️算法页面跳转
21 |
22 | 刷题页面点击题目名称:
23 |
24 | 
25 |
26 | 即可跳转道对应题目力扣做题界面:
27 |
28 | 
29 |
30 | ### 🔍全站搜索
31 |
32 | 网站已经配置了全站搜索功能,您可以在网页右上角使用它帮助你找到需要的内容。
33 |
34 | 
35 |
36 | ### 🌙夜间模式
37 |
38 | 可以在页面右上角选择切换夜间模式,帮助你获得不同的阅读体验。
39 |
40 | 
41 |
42 | 
43 |
44 |
45 |
46 | ### ❤🩹编辑修改
47 |
48 | 在每个页面文末都有**编辑此页**功能,对于错误内容可以直接提交到GitHub,我将每天审核并进行修复。
49 |
50 |
51 |

52 |
--------------------------------------------------------------------------------
/src/hr/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HR面常见面试题
3 | sidebar: heading
4 | ---
5 |
6 | ### 你的优势和劣势是什么?
7 | ### 能接受多大强度的加班?
8 | ### 简单描述一下自己是怎么样的人?
9 | ### 最近阅读哪些技术书籍,遇到技术问题是怎么去解决?
10 | ### 项目中最难的地方是哪里?你学习到了什么?
11 | ### 与同事沟通的时候,如果遇到冲突了如何解决?
12 | ### 项目中有哪些可改进的点以及很优秀的点?
13 | ### 如何评价自己学习新知识的能力?
14 | ### 目前为止,坚持得最久一件事情是什么?
15 | ### 未来的职业规划是什么?
16 | ### 最近学习了哪些新技术?
17 | ### 你的老师和同学是如何评价你的?
--------------------------------------------------------------------------------
/src/hr/rank.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | editLink: false
4 | comment: false
5 | sidebar: false
6 | ---
--------------------------------------------------------------------------------
/src/intelligence/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar: heading
3 | ---
4 |
5 |
6 |
7 | ### 利用不均匀硬币产生等概率?
8 |
9 | 连续抛两次硬币,正反面的出现有四种情况,概率依次为:
10 |
11 | 1. 两次均为正面:p * p
12 | 2. 第一次正面,第二次反面:p * (1 - p)
13 | 3. 第一次反面,第二次正面:(1 - p) * p
14 | 4. 两次均为反面:(1 - p) * (1 - p)
15 |
16 | 问题的解法就是连续抛两次硬币,如果两次得到的相同则重新抛两次;否则根据第一次(或第二次)的正面反面情况,就可以得到两个概率相等的事件。
17 |
18 |
19 |
20 | ### 5只猫5分钟捉5只老鼠,请问100分钟捉100只老鼠需要多少只猫?
21 |
22 | 5只,分析:1只猫5分钟捉1只老鼠,1只猫100分钟捉20只老鼠,5只猫100分钟捉100只老鼠。
23 |
24 |
25 |
26 | ### 3升的杯子一个,5升的杯子一个,杯子不规则形状,问怎么得到4升的水?
27 |
28 | - 5升杯子装满,全部倒给空的3升杯子,此时5升杯子有2升,3升杯子要3升
29 | - 倒掉3升杯子的全部水,再把5升杯子的2升水倒给3升杯子,此时5升杯子有0升,3升杯子有2升
30 | - 5升杯子装满水,向3升辈子倒水,倒满,此时此时5升杯子有4升,3升杯子有3升
31 |
32 |
33 |
34 | ### 用5L和6L的桶,没有刻度,怎么量出3L的水?
35 |
36 | - 6L桶装满水,向空的5升桶倒水至水满为止,此时6L桶有1升水,5L桶有5升水
37 | - 倒掉5L桶的全部水,再把6L桶的1升水倒给5L桶,此时6L桶有0升水,5L桶有1升水
38 | - 6L桶装满水,向5升桶倒水至水满为止,此时6L桶有2升水,5L桶有5升水
39 | - 倒掉5L桶的全部水,再把6L桶的2升水倒给5L桶,此时6L桶有0升水,5L桶有2升水
40 | - 6L桶装满水,向5升桶倒水至水满为止,此时6L桶有3升水,5L桶有5升水
41 |
42 |
43 |
44 | ### 晚上有四个人过桥,一次只能过两个人,但是只有一只手电筒,四个人过桥时间分别是1,2,5,8,求最短过桥时间?
45 |
46 | 假设这四人依次是甲乙丙丁:首先甲和乙过桥,甲带手电筒回来;然后丙和丁过桥,由乙带手电筒回来;最后甲再和乙一起过桥,所以最少用时间是2+1+8+2+2=15(分钟)
47 |
48 |
49 |
50 | ### 有十张扑克牌,每次可以只出一张,也可以只出两张,要出完有多少种出法?
51 |
52 | - 还有一张牌就出完10张,可能的情况有两种,从9到10和从8到10,已知了从0到9的出法有N种,如果再知道从0到8的出法有P种,那么从0到10级的出法就是N+P,那么可得出:
53 | - F(9)=N;F(8)=P;F(10)=N+P;F(10)=F(9)+F(8);
54 | - 又有:F(1)=1;F(2)=2最后推出:F(10)=89
55 |
56 |
57 |
58 | ### 两根香,一根烧完1小时,如何测量15分钟?
59 |
60 | 开始时一根香两头点着,一根香只点一头,两头点着的香烧完说明过去了半小时,这时将只点了一头的香另一头也点着,从这时开始到烧完就是15分钟。
61 |
62 |
--------------------------------------------------------------------------------
/src/intelligence/rank.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | editLink: false
4 | comment: false
5 | sidebar: false
6 | ---
7 |
8 | ### 如何用[0,4]的随机数生成[0,6]的随机数?(1次)
9 |
10 | ### 判断一个数的二进制里面有多少个1? (1次)
11 |
12 | ### 怎么判断一个数是不是2的幂? (1次)
13 |
14 | ### 1000个银币中有一个假币,用天平找找几次? (1次)
15 |
--------------------------------------------------------------------------------
/src/interview/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | pageInfo: false
3 | editLink: false
4 | comment: false
5 | sidebar: heading
6 | ---
7 |
8 | ## 🔆面经提交的意义
9 |
10 | 为了更方便广大求职者寻找工作机会,同时也有利于本站的持续发展,希望您在每次面试之后,将面试过程中的内容记录下来并提交到的网站。
11 |
12 | 我们会将您提交的内容汇总展示为 [**面试分类**] 和 [**题目频次**] 等各个模块,同时针对面试经验中出现的题目,我们会不断更新我们网站上的内容。
13 |
14 | 这样可以帮助更多的学习者了解真实的面试过程,并更好地应对面试中出现的问题。
15 |
16 |
17 | ## 📬提交方式
18 |
19 | 可以添加我的个人微信或者发送到邮箱:
20 |
21 | - 微信账号:zijing5277
22 |
23 |
24 | - 邮箱:944741457@qq.com
--------------------------------------------------------------------------------
/src/introduction/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar: heading
3 | pageInfo: false
4 | editLink: false
5 | comment: false
6 | ---
7 |
8 |
9 |
10 | CSView | 计算机面试知识汇总
11 |
12 |
13 |
14 |
15 |
16 |
17 | 👁🗨CSView介绍
18 |
19 | CSView是一个互联网面试知识学习和汇总项目,包括**面试高频算法、系统设计、计算机网络、操作系统、cpp语言基础、Java语言基础、golang语言基础、MySQL、Redis、K8s、消息队列**等常见面试题。
20 |
21 | 与传统的学习网站不同的是,**CSView的内容来源于面经,并且网站和公众号会不断汇总面经内容来进行迭代**。真实的面试问什么,网站就写什么,这样更有助面试者了解面试情形。同时项目还会定期分享面试经验和互联网实用知识,帮助大家更好准备面试。
22 |
23 | 
24 |
25 |
26 |
27 | 🧑💻适用者
28 |
29 |
30 | **该项目适用于**:
31 |
32 | - 准备实习/校招面试的人
33 | - 面试前自查基础知识掌握程度的人
34 | - 社招补充基础的人
35 | - 喜欢抽象事物的人
36 | - 爱好仙子伊布的人
37 |
38 |
39 |
40 |
41 |
42 | 💻项目来源
43 |
44 |
45 | 我叫zijing,是**CSView**的发起人。作为一个参加过22届秋招的人,我投递参加过**数十场校招面试,看过上百篇面经**,最后成功拿下了**字节、百度**等互联网公司的offer。我发现大多数互联网校招的准备方法仍有迹可循,围绕着**项目经历、语言基础、计算机网络,数据库、操作系统**等询问的基础知识(一般被称为八股文),在更为充分的准备下,明显会有更高面试通过率。
46 |
47 | 然而,现在互联网上存在大量低质量、错误频出、无用内容占多数的校招和八股文网站和文档分享,这会浪费面试准备者大量时间。为了避免时间浪费,让同学们把握面试中的要点内容,我找了几个朋友一起整理分享,于是CSView这个项目应运而生。
48 |
49 | 虽然现在有很多不足之处,但是好在开发迭代的速度很快,我们每天都在完善网站的内容,与面试准备者进行交流,帮助大家能找到更满意的工作。
50 |
51 | 当然,如果本站内容对你准备学习知识有帮助,您可以给一个**打赏(您的打赏将被放在网站的[贡献页面](https://www.csview.cn/website-contribution))**或者是**简单地去[GitHub](https://github.com/zijing2333/CSView)给项目点一个star**,作为对我们工作内容的认可。
52 |
53 | ::: tip CSView的来源
54 |
55 | 为什么网站和项目的名称叫CSView呢?CS是计算机科学Computer Science的缩写,而View在汉语里有**视野、个人意见、见解、(理解或思维的)方法和风景**的意思,在使用本站的过程中,我们希望:
56 |
57 | - 网站可以带给你不一样的理解和思维
58 |
59 | :::
60 |
61 |
62 |
63 | ✨项目特点
64 |
65 |
66 | **贴合面试**:网站的题目都是从数百篇面经中提取出来的**最常考**的题目,准备这些题目通常是性价比最高。我们并不会把诸如“**什么是数据库**”这类的问题放在网站上,一是没必要,二是浪费面试者的宝贵时间。
67 |
68 | **高质量回答**:针对高频次的题目网站都会给出一定的回答,回答介于书面语和口头语之间,既不失阅读时的严谨性,也不失理解上的简易性。
69 |
70 | **体验良好**:我们曾尝试过WordPress、MkDocs、Hexo等多种框架搭建网站,最后选择了功能完善且阅读体验更好的vuepress架构,并采用了vuepress-theme-hope主题。网站的**页面布局、内容分类、字体颜色、功能选配、代码块主题和图片配色**等都是精心调试过的,旨在带来更好的使用体验。
71 |
72 | **开源免费**:项目承诺所有内容完全免费,并且在[GitHub](https://github.com/zijing2333/CSView)可以获取一切关于本站的内容。
73 |
74 | **共商共建**:可以在[开发日志](https://www.csview.cn/development-log/)看到网站更新工作和进展,我们会不断优化网站的每一处内容,网站内容也会根据面经和实际需求**每天更新**,及时修复存在的错误。任何人都可以参与到项目的建设中来,任何人都可以贡献内容到网站,贡献内容的人将会出现在网站的作者栏。
75 |
76 |
77 |
78 |
79 |
80 |
81 | ✍作者
82 |
83 | **枫长**:算法页面作者,某C9高校硕士,**曾在字节跳动和阿里云各实习两个月,力扣刷题800多道**,经常参加算法周赛,算法解题经验丰富。主要技术栈是C++。
84 |
85 |
86 |
87 | **LH**:985硕士,**22年秋招上岸字节核心部门**,是一个唱歌很好听的小哥哥。主要技术栈是C++。
88 |
89 |
90 |
91 | **jjd**:操作系统和C++页面作者,**国内top3计算机专业硕士在读**,本科专业top5%,曾获数学建模国奖一等奖。
92 |
93 |
94 |
95 | **xmy**:Java页面作者,985计算机硕士,曾在网易实习三个月,爱好打星际。主要技术栈是Java。
96 |
97 |
98 |
99 | **fawn**:CSView的图片绘制人,华五计算机专业,**高考680分+**,爱好睡觉。
100 |
101 |
102 |
103 | **小羊**:专业的图案创意设计者,爱好不加班。
104 |
105 |
106 |
107 | **子敬**:某985大学软件工程专业读研二,**仙子伊布爱好者**,喜欢读哲学、历史和养生学。主要技术栈是Golang。
108 |
109 |
110 |
111 |
112 | 🛠技术支持
113 |
114 | **开发测试**:[腾讯云服务器](https://github.com/zijing2333/CSView)
115 |
116 | **项目框架**:[vuepress2.0](https://v2.vuepress.vuejs.org/)
117 |
118 | **主题**:[vuepress-theme-hope](https://theme-hope.vuejs.press/)
119 |
120 | **代码托管和CDN加速**:[Vercel](https://vercel.com/)
121 |
122 | **图床**:[聚和图床](https://www.superbed.cn/)
123 |
124 | **图标**:[iconfont](https://www.iconfont.cn/)
125 |
126 | **页面语法**:MarkDown-Enhance
127 |
128 |
129 |
130 |
131 | ⚠️声明
132 |
133 | 网站为本人整合创作,禁止整合恶意搬运、分享,且严禁将网站内容整合搬运到任何公众号。未按要求注明来源的内容请联系我整改或者删除。
134 |
135 |
136 |
137 |
138 | 🦀特别鸣谢
139 |
140 | **特别感谢**[xiaolingcoding](https://xiaolincoding.com/)对本站创作和内容的支持,本站复用xiaolingcoding内容是为了带来更高质量的内容,同时也推荐大家去[xiaolingcoding](https://xiaolincoding.com/)系统学习计算机基础知识,这是一个质量极高的学习网站。
141 |
142 | **特别感谢**[Mr.Hope](https://mrhope.site/)(vue-theme-hope主题开发者)项目开发中提供的技术支持及问题解决方案。
143 |
144 |
145 |
146 |
147 | 📅未来计划
148 |
149 | - [ ] 面试题频次排序功能实现
150 | - [ ] 面经提交功能实现
151 | - [ ] 招聘汇总信息上线
152 | - [ ] 面经总结页面上线
153 | - [ ] 使用algolia重新构建网站索引
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/src/java/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Java
3 | pageInfo: false
4 | editLink: false
5 | author: xmy
6 | comment: false
7 | ---
8 |
9 | ------
10 |
11 |
12 |
13 | # [基础](./summary.md)
14 |
15 | # [集合](./collection.md)
16 |
17 | # [并发](./concurrent.md)
18 |
19 | # [JVM](./jvm.md)
20 |
21 | # [Spring](./spring.md)
22 |
--------------------------------------------------------------------------------
/src/java/collection.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 集合
3 | author: xmy
4 | ---
5 |
6 | ### ArrayList、LinkedList和Vector的区别?
7 | - ArrayList基于数组,查询较快,末尾插入O(1),中间i处插入O(n-i),需要移动元素,可通过序号快速获取对象,线程不安全,有预留的内存空间
8 |
9 | - LinkedList基于双向链表,末尾插入O(1),中间i处插入O(n-i),但不需要移动元素,不可通过序号快速获取对象,线程不安全,没有预留的内存空间,但每个节点都有两个指针占用了内存
10 |
11 | - Vector和ArrayList实现上基本相同,区别在于Vector是线程安全的,其各种增删改查方法加了synchronized修饰
12 |
13 | ### ArrayList扩容机制
14 | 通过一次ArrayList创建和add的流程分析扩容机制:
15 |
16 | 首先,ArrayList有三个构造函数:
17 |
18 | ```java
19 | public ArrayList(int initialCapacity) {
20 | if (initialCapacity > 0) {
21 | this.elementData = new Object[initialCapacity];
22 | } else if (initialCapacity == 0) {
23 | this.elementData = EMPTY_ELEMENTDATA;
24 | } else {
25 | throw new IllegalArgumentException("Illegal Capacity: "+
26 | initialCapacity);
27 | }
28 | }
29 | ```
30 |
31 | ```java
32 | public ArrayList() {
33 | this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
34 | }
35 | ```
36 |
37 | ```java
38 | public ArrayList(Collection extends E> c) {
39 | elementData = c.toArray();
40 | if ((size = elementData.length) != 0) {
41 | // c.toArray might (incorrectly) not return Object[] (see 6260652)
42 | if (elementData.getClass() != Object[].class)
43 | elementData = Arrays.copyOf(elementData, size, Object[].class);
44 | } else {
45 | // replace with empty array.
46 | this.elementData = EMPTY_ELEMENTDATA;
47 | }
48 | }
49 | ```
50 |
51 | 以及几个核心属性:
52 |
53 | ```java
54 | private static final int DEFAULT_CAPACITY = 10;
55 | private static final Object[] EMPTY_ELEMENTDATA = {};
56 | private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
57 | transient Object[] elementData;
58 | private int size;
59 | ```
60 |
61 | 由此可以分析出:
62 |
63 | 如果创建空的Arraylist对象,则可以用无参构造器或其它两个分别以0和空的集合作为参数进行创建。当用无参构造器创建时,会将其内容数组elementData指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA这个单例,而用其它两个构造器创建空的ArrayList对象时,会令elementData指向EMPTY_ELEMENTDATA这个单例
64 |
65 | 如果创建非空的,则只能用两个有参构造器进行创建,它们都会将elementData指向新创建的Object[]对象
66 |
67 | 再来看看add:
68 |
69 | ```java
70 | public boolean add(E e) {
71 | ensureCapacityInternal(size + 1); // Increments modCount!!
72 | elementData[size++] = e;
73 | return true;
74 | }
75 | ```
76 |
77 | ```java
78 | public void add(int index, E element) {
79 | rangeCheckForAdd(index);
80 |
81 | ensureCapacityInternal(size + 1); // Increments modCount!!
82 | System.arraycopy(elementData, index, elementData, index + 1,
83 | size - index);
84 | elementData[index] = element;
85 | size++;
86 | }
87 | ```
88 |
89 | 后者在前者的基础上只是加了一些对数组越界和插入时移动部分对象的处理,扩容的核心则都在ensureCapacityInternal这个函数里
90 |
91 | ```java
92 | private void ensureCapacityInternal(int minCapacity) {
93 | if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
94 | minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
95 | }
96 |
97 | ensureExplicitCapacity(minCapacity);
98 | }
99 | ```
100 |
101 | 其中`minCapacity`可以理解为扩容后容量的最小值,假设调用无参构造器创建了一个`ArrayList`对象,则初始状态下其`size=0`,`DEFAULT_CAPACITY=10`。此时我们对其调用`add(new Object())`,那么首先会调用`ensureCapacityInternal(0 + 1)`,意为新加入了一个对象,此时容量应至少为`1`。随后,判断该`ArrayList`是否是用无参构造器创建的,如果是,将`minCapacity`设为`max(DEFAULT_CAPACITY, minCapacity)`,即默认容量够用了就不用再扩容。随后调用`ensureExplicitCapacity(minCapacity)`
102 |
103 | ```java
104 | private void ensureExplicitCapacity(int minCapacity) {
105 | modCount++;
106 |
107 | // overflow-conscious code
108 | if (minCapacity - elementData.length > 0)
109 | grow(minCapacity);
110 | }
111 | ```
112 |
113 | 此时判断如果应该达到的容量超过现有数组的长度,则需要扩容,扩容就调用`grow(minCapacity)`方法
114 |
115 | ```java
116 | private void grow(int minCapacity) {
117 | // overflow-conscious code
118 | int oldCapacity = elementData.length;
119 | int newCapacity = oldCapacity + (oldCapacity >> 1);
120 | if (newCapacity - minCapacity < 0)
121 | newCapacity = minCapacity;
122 | if (newCapacity - MAX_ARRAY_SIZE > 0)
123 | newCapacity = hugeCapacity(minCapacity);
124 | // minCapacity is usually close to size, so this is a win:
125 | elementData = Arrays.copyOf(elementData, newCapacity);
126 | }
127 | ```
128 |
129 | 首先设定新的容量为原来的`3/2`,再判定加完这部分是否够用,如果不够用就将新容量设定为刚刚好。这时如果新容量超出了系统规定的最大值,则调用`hugeCapacity(minCapacity)`将其设定为一个合理的最大值。最后将elementData拷贝到新容量的Object[]中。
130 |
131 | ```java
132 | private static int hugeCapacity(int minCapacity) {
133 | if (minCapacity < 0) // overflow
134 | throw new OutOfMemoryError();
135 | return (minCapacity > MAX_ARRAY_SIZE) ?
136 | Integer.MAX_VALUE :
137 | MAX_ARRAY_SIZE;
138 | }
139 | ```
140 |
141 | 至此一次扩容算是完毕了。
142 |
143 | **总结一下就是无参构造的第一次add扩容到10,随后每当加满了就扩容到原来的3/2。有参构造的如果构造的是空list,则第一次add扩容到1,第二次扩容到2,第三次扩容到3,第四次扩容到4,第五次扩容到6,再加满扩容到9,...,后面都是3/2了。有参构造非空list,按前面的序列来。最大容量为`Integer.MAX_VALUE=0x7fffffff`**
144 |
145 | ### HashMap、HashSet和HashTable的区别
146 |
147 | - HashMap线程不安全,效率高一点,可以存储null的key和value,null的key只能有一个,null的value可以有多个。默认初始容量为16,每次扩充变为原来2倍。创建时如果给定了初始容量,则扩充为2的幂次方大小。底层数据结构为数组+链表,插入元素后如果链表长度大于阈值(默认为8),先判断数组长度是否小于64,如果小于,则扩充数组,反之将链表转化为红黑树,以减少搜索时间。
148 |
149 | - HashTable线程安全,效率低一点,其内部方法基本都经过synchronized修饰,不可以有null的key和value。默认初始容量为11,每次扩容变为原来的2n+1。创建时给定了初始容量,会直接用给定的大小。底层数据结构为数组+链表。它基本被淘汰了,要保证线程安全可以用ConcurrentHashMap。
150 |
151 | - HashSet是基于HashMap实现的,只是value都指向了一个虚拟对象,只用到了key
152 |
153 | ### HashSet、LinkedHashSet和TreeSet的区别
154 |
155 | - LinkedHashSet是HashSet子类,在HashSet的基础上能过够按照添加的顺序遍历
156 |
157 | - TreeSet底层使用红黑树,插入时按照默认/自定义的key排序规则指定插入位置
158 |
159 | ### 总结
160 | - Collection下主要有List,Set,Map三个接口
161 |
162 | - List和Set是继承了Collection接口
163 |
164 | - Map只是依赖了Collection接口,不存在父子关系
165 |
166 | - List主要有ArrayList,LinkedList,Vector
167 |
168 | - Set主要有HashSet,TreeSet,LinkedHashSet
169 |
170 | - Map主要有HashMap,HashTable,TreeMap,ConcurrentHashMap
171 |
172 | - 当我们要存键值对,以便通过键值访问数据时,就用Map,此时需要排序就用TreeMap,不需要就用HashMap,需要线程安全就用ConcurrentHashMap
173 |
174 | - 当我们只需要存对象时,就用Collection,需要保证唯一性就用Set,不需要就用List。用Set时,需要保证顺序就用TreeSet,不需要就用HashSet。用List时,如果是频繁查询,较少增删的场景,就用ArrayList,如果是频繁增删,较少查询的场景就用LinkedList,如果要保证线程安全就用Vector
--------------------------------------------------------------------------------
/src/java/jvm.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Java
3 | author: xmy
4 | ---
5 |
6 | ### 内存区域
7 | 
8 |
9 | HotSpot在JDK1.8之前方法区就是永久代,永久代就是方法区。
10 |
11 | JDK1.8后删除了永久代,改为元空间,元空间在直接内存中。方法区就是元空间,元空间就是方法区。
12 |
13 | 创建一个线程,JVM就会为其分配一个私有内存空间,其中包括PC、虚拟机栈和本地方法栈
14 |
15 | **PC**
16 |
17 | 用来指示下一个执行的字节码指令,基于这一点就能实现代码的控制流程
18 |
19 | 为了确保每个线程切换回来都能从上次的位置继续运行,PC必须是线程私有的,切换出去时需保存各自的PC
20 |
21 | **虚拟机栈**
22 |
23 | 虚拟机栈中一个栈帧压入就对应一个方法的调用,栈帧弹出就对应方法返回。栈帧中包含:局部变量表、操作数栈、动态链接、方法出口信息。
24 |
25 | 局部变量表也就是常说的栈内存,用来存储基本类型和引用
26 |
27 | HotSpot不支持动态扩展虚拟机栈,在创建线程时就确定了虚拟机栈的最大深度,如果申请不了这么多内存,就会抛出OOM错误,如果线程在运行时调用了很多方法,到达了栈的最大深度,就会抛出SOF错误
28 |
29 | **本地方法栈**
30 |
31 | 和虚拟机栈相同,区别仅在于虚拟机栈中是java方法,本地方法栈中是native方法,但HotSpot中已经将二者合而为一了。
32 |
33 | **堆**
34 |
35 | JVM中最大的一块内存空间,所有对象实例和数组都在这里分配内存,所有线程共享堆内存。
36 |
37 | JDK1.7开始默认开启了逃逸分析,如果一个对象只在一个线程中被引用了,则该对象可以直接在栈上分配内存空间。
38 |
39 | 堆也叫GC堆,是垃圾回收的主要区域。为了便于垃圾回收,JDK1.8之前将堆分为三个部分:
40 |
41 | 1. 新生代
42 | 2. 老年代
43 | 3. 永久代
44 |
45 | 而1.8之后将永久代删除了,取而代之的是元空间,元空间则在直接内存中。
46 |
47 | 此外,新生代还细分为eden、from survivor(s0)和to survivor(s1)
48 |
49 | 当新对象实例产生时,年龄为0,首先被分配在eden里,在一次gc后,如果还存活,就被扔到survivor里,并且年龄+1,当年龄增加到一定程度后就被扔到老年代里。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。
50 |
51 | **方法区**
52 |
53 | 存放被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
54 |
55 | 1.8之前是永久代,属于堆内存。1.8之后是元空间,属于直接内存。
56 |
57 | 永久代受JVM创建时分配的最大堆内存限制,而元空间则受系统内存限制,可以存储更多。
58 |
59 | **常量池**
60 |
61 | 分为字符串常量池和运行时常量池
62 |
63 | 1.8之后字符串常量池在堆中,而运行时常量池在元空间
64 |
65 | **直接内存**
66 |
67 | 在JVM进程的内存空间之外,属于系统内存。
68 |
69 | JVM可通过native方法对其进行直接操作,而无需在使用时将其拷贝到JVM内存区。
70 |
71 | ### 对象创建过程
72 | 
73 |
74 | 1. **类加载检查:**
75 |
76 | JVM遇到一条new指令时,先检查能不能在常量池中定位到该类的符号引用,并检查这个符号引用代表的类是否已被加载、解析和初始化。如果没有就要先进行类加载。类已被加载就通过检查。
77 |
78 | 2. **分配内存:**
79 |
80 | 类加载检查通过后JVM为新对象分配内存,对象所需的内存大小在类加载完成后就确定了,JVM会在堆中按照**指针碰撞**或**空闲列表**的方式为对象划分出一块空间,选择哪种方式会根据垃圾收集器的算法而定。此外,内存分配还要保证线程安全,JVM采用**CAS+失败重试**或**TLAB**的方式保证线程安全。
81 |
82 | CAS+失败重试:乐观锁的一种实现,每次占用资源不加锁,而是不断尝试占用。
83 |
84 | TLAB:线程创建时预先在堆中给线程分配一块内存,称为TLAB,专门用来存放该线程运行过程中创建的对象,而TLAB满了时,采用上述CAS在堆的其它内存中分配
85 |
86 | 3. **初始化零值:**
87 |
88 | 将对象的字段设为默认零值,不包括对象头
89 |
90 | 4. **设置对象头:**
91 |
92 | 在对象头中设置这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄、是否启用偏向锁等信息
93 |
94 | 5. **执行init方法:**
95 |
96 | 初始化对象,即按照程序员写的构造方法给对象进行初始化。
97 | ### GC
98 |
99 | **内存分配与回收**
100 |
101 | 新对象优先被分配在eden里,年龄设置为0,经历第一次gc后如果还存活,就被扔到survivor中,并且年龄+1,随后每经历一次gc如果还存活就年龄+1,如果年龄超过了上限(默认15),就被扔到老年代中。通过-XX:MaxTenuringThreshold设置上限。
102 |
103 | 此外,JVM还有动态年龄判定机制:如果在survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到年龄超过上线。
104 |
105 | 如果是过大的对象,为了避免其来回复制,可以在创建时直接扔到老年代里。通过-XX:PretenureSizeThreshold设置,只支持Serial和ParNew。
106 |
107 | 
108 |
109 | hotspot中gc分为两类:部分收集partial gc和全收集full gc。
110 |
111 | 部分收集又分minor gc、major gc和mixed gc
112 |
113 | minor gc:只对新生代进行回收
114 |
115 | major gc:只对老年代进行回收(有时也指代full gc)
116 |
117 | mixed gc:对整个新生代和部分老年代进行回收
118 |
119 | 全收集full gc:对整个堆和方法区(hotspot中的元空间)进行回收
120 |
121 | **判别对象、常量、类死亡的方法**
122 |
123 | - **对象**
124 |
125 | 1. **引用计数法:**
126 |
127 | 对象中设置一个引用计数器,每当该对象被引用时,引用计数器就会+1,失去一个引用时就会-1。引用计数器为0时就代表已经死亡,不会再被引用了。这种判别方式有个缺点,如果两个对象互相引用,但又没有外界对它们的引用,则它们引用计数都为1,会一直存在,但没有意义。
128 |
129 | 2. **可达性分析法:**
130 |
131 | 设置一组对象为**gc roots**,如果一个对象没有能到达任何一个gc root的引用链,则判别这个对象死亡。一般一个线程启动后并列创建的一组对象会构成gc roots,gc roots内部引用的对象就是非gc root。
132 |
133 | - **常量**
134 |
135 | 没有被任何对象引用时就是废弃的
136 |
137 | - **类**
138 |
139 | 同时满足如下三点就是无用的类
140 |
141 | 1. 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
142 | 2. 加载该类的 ClassLoader 已经被回收。
143 | 3. 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类
144 | 的方法。
145 |
146 | **引用类型都有哪些?**
147 | 1. **强引用**
148 |
149 | ```java
150 | Object strong = new Object();
151 | ```
152 |
153 | 一个对象如果被引用,且最高级别是强引用,就不会被回收。
154 |
155 | 2. **软引用**
156 |
157 | ```java
158 | SoftReference