计算机基础面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

计算机基础阅读 05月27日 21:17

ASCII 码中数字字符怎么和整数互相转换?

数字字符和 ASCII 码怎么互相转换?数字字符 '0'-'9' 的 ASCII 值是 48-57,连续排列。核心转换就一个公式:数字字符的 ASCII 值 = 数字值 + 48(即 ord('0'))。字符转整数: 用字符减去 '0' 的 ASCII 值即可。int num = ch - '0'; // C/Javaint num = ord(ch) - ord('0') # Python整数转字符: 数字加上 '0' 的 ASCII 值。char ch = num + '0'; // C/Javachar = chr(num + ord('0')) # Python判断是否为数字字符:// C/Javaif (ch >= '0' && ch <= '9')// Pythonif '0' <= ch <= '9'为什么是减 '0' 而不是减 48?语义清晰。ch - '0' 直接表达"求这个字符代表的数字",而 ch - 48 需要读者心算 48 是什么。另外,ASCII 并非唯一编码标准,用 '0' 做基准在 EBCDIC 等编码下逻辑不变(虽然值不同),代码可移植性更好。实战:手写字符串转整数不用 parseInt / int(),手动实现:def str_to_int(s): num = 0 for c in s: if not ('0' <= c <= '9'): break num = num * 10 + (ord(c) - ord('0')) return num每一轮把已有结果左移一位(乘 10),再加上新数字位。追问:负数怎么处理?跳过开头的 '-',按正数转换,最后取反即可。注意 "-0" 和溢出的边界情况,这是面试中常见的 follow-up。
计算机基础阅读 05月27日 21:17

如何判断字符串是否为纯 ASCII 字符串

核心思路ASCII 字符的编码值范围是 0–127(0x00–0x7F),共 128 个字符。判断一个字符串是否为纯 ASCII,本质就是检查其中每个字符的编码值是否都小于 128。任何编码值 ≥ 128 的字符都是非 ASCII 字符(如中文、emoji、法文重音字母等)。最简实现Python 一行搞定:s.isascii() # Python 3.7+内部等价于 all(ord(c) < 128 for c in s),发现非 ASCII 字符立即返回 False,时间复杂度 O(n)。JavaScript 用正则:/^[\x00-\x7F]*$/.test(str)\x00-\x7F 就是 0–127 的十六进制表示,正则引擎会逐字符匹配,命中非 ASCII 即失败。Java 17+ 用内置方法:str.chars().allMatch(Character::isAscii)Go 逐 rune 判断:func isASCII(s string) bool { for _, r := range s { if r > 127 { return false } } return true}C 逐字节判断(注意必须用 unsigned char,否则高位字符会被当作负数):bool is_ascii(const char *s) { for (size_t i = 0; s[i]; i++) if ((unsigned char)s[i] > 127) return false; return true;}面试追问Q: 空字符串算 ASCII 吗?算。空集合不包含非 ASCII 字符,逻辑上为真,isascii() 和正则方式也返回 True。Q: UTF-8 编码下 ASCII 字符有什么特殊性?ASCII 字符在 UTF-8 中只占 1 字节,且编码值与 ASCII 完全一致。因此可以用 len(s) == len(s.encode("utf-8")) 间接判断:长度不等说明存在多字节字符。Q: 如何用 SIMD 加速?对长字符串,可以将每 16 字节加载到 SIMD 寄存器,与 127 做比较,一次判断 16 个字符是否都在 ASCII 范围内,比逐字符快一个数量级。Rust 的 bstr 库已内置此优化。边界注意控制字符(0–31)也是合法 ASCII,别误判C/C++ 中 char 是否有符号由实现定义,必须强转 unsigned charUnicode 组合字符(如 é = e + \u0301)各部分均在 ASCII 范围内,但视觉上是非 ASCII 外观,需根据业务场景决定是否额外处理
计算机基础阅读 05月27日 10:50

XML 中的 CDATA 是什么?什么时候需要用 CDATA?

CDATA(Character Data)是 XML 里的一个特殊标记,告诉解析器"这段内容别解析,原样保留"。当你需要在 XML 中放代码、HTML 片段或包含大量 <、>、& 的文本时,CDATA 省去逐个转义的麻烦。基本语法<code> <![CDATA[ if (x < 10 && y > 5) { return "ok"; } ]]></code><![CDATA[ 和 ]]> 之间的内容,XML 解析器不会尝试解析标签或实体引用,全部当作原始文本处理。什么时候需要 CDATA嵌入代码:JavaScript、SQL、CSS 里大量使用 <、>、&&,不用 CDATA 就得写成 <、>、&&,可读性极差。<script> <![CDATA[ function check() { if (count < 10 && status === "active") { return true; } } ]]></script>嵌入 HTML 片段:RSS feed 里经常包含 HTML 内容,CDATA 是标准做法。<description> <![CDATA[ <p>这是一段<strong>HTML</strong>内容</p> ]]></description>嵌入 SQL 查询:MyBatis、Hibernate 的 XML 映射文件里写 SQL,比较运算符必须转义或用 CDATA。<select id="findActive"> <![CDATA[ SELECT * FROM users WHERE age > 18 AND score >= 60 ]]></select>CDATA 的限制不能嵌套:CDATA 内部不能出现 ]]>,因为解析器会把第一个 ]]> 当作 CDATA 结束标记。如果内容里确实需要 ]]>,得拆成两个 CDATA 节:]]]><![CDATA[>。大小写敏感:必须是 CDATA,写成 cdata 或 Cdata 都不对。空白保留:CDATA 里的换行和缩进会原样保留,包括你不想保留的。格式化 XML 时注意别误改 CDATA 内的空白。不能做部分转义:CDATA 是全有或全无的——整个内容都不解析。如果只需要转义个别字符,用实体引用 < > 更精确。CDATA vs 实体引用| 特性 | CDATA | 实体引用 ||------|-------|----------|| 语法 | <![CDATA[...]]> | < > & || 适用范围 | 大段文本 | 单个字符 || 可读性 | 高,原文可读 | 低,需要还原 || 灵活性 | 低,整个块不解析 | 高,精确控制 |经验法则:超过 3 个特殊字符就用 CDATA,少于 3 个用实体引用。常见误区CDATA 不是数据类型:CDATA 只是告诉解析器别解析,它不改变数据的含义。解析后 <![CDATA[hello]]> 和 hello 是等价的——应用程序拿到的是同样的字符串。CDATA 不影响验证:XSD 验证时,CDATA 内的内容同样会被检查是否符合类型约束。CDATA 只跳过解析,不跳过验证。浏览器中的 CDATA:XHTML 里曾经用 //<![CDATA[ 包裹 JavaScript,但 HTML5 不需要——<script> 标签的内容本身就不被当作 XML 解析。这个用法已经过时了。
计算机基础阅读 05月27日 10:49

XML 和 JSON 有什么区别?什么时候该用 XML?

XML 和 JSON 是两种最常用的数据交换格式,但它们的定位不同:XML 是标记语言,擅长表达文档结构;JSON 是数据格式,擅长表达结构化数据。现代 Web 开发 90% 的场景用 JSON,但 XML 在特定领域仍然不可替代。核心区别| 特性 | XML | JSON ||------|-----|------|| 定位 | 标记语言,面向文档 | 数据格式,面向数据 || 语法 | 标签闭合 <name>值</name> | 键值对 "name": "值" || 数据类型 | 无内置类型,都是字符串 | string、number、boolean、null、array、object || 注释 | 支持 <!-- --> | 不支持 || 命名空间 | 支持,避免标签冲突 | 不支持 || 验证 | DTD / XSD 成熟方案 | JSON Schema(较新,工具链不完善) || 冗余度 | 高(开闭标签重复) | 低 || 解析速度 | 慢(DOM/SAX) | 快(原生支持) |一句话概括:XML 能做文档,JSON 只能做数据;JSON 传输快,XML 验证强。什么时候必须用 XML包含文档内容:XML 的标签能表达语义和层级(标题、段落、列表),JSON 的键值对做不到。Office 文档(docx、xlsx)底层是 XML,RSS/Atom feed 也是 XML——这些场景需要混合内容和结构。需要严格验证:XSD 可以定义精确的类型约束(值范围、正则模式、枚举),JSON Schema 功能弱得多。金融、医疗、政府数据交换标准(如 HL7、FHIR 的 XML 格式)依赖 XSD 验证。命名空间:多个词汇表组合时,命名空间避免标签冲突。SOAP、XHTML、SVG 都用命名空间。JSON 没有这个能力。遗留系统集成:企业里大量旧系统只认 XML。SAP、Oracle、银行接口——你不想用也得用。JSON 的优势场景Web API:RESTful API 用 JSON 是事实标准。体积小、解析快、前端原生支持,没有理由用 XML。配置文件:package.json、tsconfig.json、.eslintrc——开发工具链已经全面倒向 JSON(以及 JSON 超集如 JSON5、YAML)。移动端和低带宽场景:JSON 比 XML 小 30-50%,解析快 2-3 倍。移动网络下这个差距很实际。NoSQL 数据库:MongoDB、CouchDB 存储 JSON 文档,查询天然适配。同一数据的格式对比<!-- XML --><book id="1" category="web"> <title>XML Guide</title> <price>39.95</price> <tags> <tag>XML</tag> <tag>Programming</tag> </tags></book>{ "id": 1, "category": "web", "title": "XML Guide", "price": 39.95, "tags": ["XML", "Programming"]}XML 版本 156 字节,JSON 版本 98 字节。数据量大的时候,这个差距更明显。格式互转XML 和 JSON 互转不是无损的——XML 的属性、命名空间、混合内容在 JSON 里没有对应概念:XML 属性(<book id="1">)转 JSON 时变成普通字段,丢失"这是属性"的语义XML 混合内容(<p>文字<b>加粗</b>继续</p>)转 JSON 需要特殊处理JSON 的数组类型转 XML 时只能用重复标签模拟所以别指望"先写 XML 再转 JSON"或反过来——两种格式的数据模型不同,互转会丢信息。选型决策简单判断:如果数据是给人读的文档,用 XML;如果是给程序消费的结构化数据,用 JSON。如果两者都涉及(比如带格式的富文本数据),考虑用 JSON 做传输、XML 做存储,或者直接用 Markdown + JSON 元数据的组合方案。
计算机基础阅读 05月27日 10:49

XML Schema 和 DTD 有什么区别?XSD 为什么取代了 DTD?

XML Schema(XSD)和 DTD 都用来定义 XML 文档的结构和约束,但能力差距很大。XSD 是 DTD 的现代替代方案——基于 XML 语法、支持数据类型、支持命名空间、可扩展可继承。DTD 语法简单但功能有限,新项目几乎不再使用。核心区别| 特性 | XML Schema (XSD) | DTD ||------|------------------|-----|| 语法 | XML 格式,可用 XML 解析器处理 | 自有语法,不是 XML || 数据类型 | 丰富内置类型(string、int、date、boolean 等) | 只有字符串,没有类型区分 || 命名空间 | 原生支持 | 不支持 || 类型继承 | 支持 extension 和 restriction | 不支持 || 可重用性 | 支持类型导入和引用 | 难以复用 || 约束精度 | 可定义值范围、正则模式、枚举 | 只能定义元素出现次数 |简单说:XSD 能做的 DTD 做不了(类型约束、命名空间),DTD 能做的 XSD 都能做且做得更好。XSD 基础结构XSD 本身是 XML 文档,根元素是 <xs:schema>:<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="book" type="BookType"/> <xs:complexType name="BookType"> <xs:sequence> <xs:element name="title" type="xs:string"/> <xs:element name="price" type="xs:decimal"/> <xs:element name="publishDate" type="xs:date"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> </xs:complexType></xs:schema>complexType 定义包含子元素或属性的复杂类型,simpleType 定义带约束的简单类型。XSD 的约束能力XSD 比 DTD 强的地方在于精确约束:<!-- 值范围约束 --><xs:simpleType name="AgeType"> <xs:restriction base="xs:integer"> <xs:minInclusive value="0"/> <xs:maxInclusive value="120"/> </xs:restriction></xs:simpleType><!-- 正则约束 --><xs:simpleType name="EmailType"> <xs:restriction base="xs:string"> <xs:pattern value="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"/> </xs:restriction></xs:simpleType><!-- 枚举约束 --><xs:simpleType name="StatusType"> <xs:restriction base="xs:string"> <xs:enumeration value="active"/> <xs:enumeration value="inactive"/> </xs:restriction></xs:simpleType>DTD 只能声明元素存在和出现次数,无法约束值的格式和范围。类型继承和扩展XSD 支持两种继承方式:extension:在基础类型上添加新元素或属性restriction:在基础类型上收紧约束<!-- 扩展:在 PersonType 上加 department --><xs:complexType name="EmployeeType"> <xs:complexContent> <xs:extension base="PersonType"> <xs:sequence> <xs:element name="department" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent></xs:complexType>这是 DTD 完全做不到的——DTD 没有类型体系,每个元素定义都是独立的。在 XML 中引用 XSD<book xmlns="http://www.example.com/books" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/books books.xsd"> <title>XML Guide</title> <price>49.99</price> <publishDate>2024-01-15</publishDate></book>schemaLocation 属性成对出现:命名空间 URI + XSD 文件路径。解析器会根据 XSD 验证文档内容。什么时候还在用 DTD?DTD 在 2025 年基本只剩这些场景:维护遗留系统(改 DTD 风险比替换小)HTML5 的 DOCTYPE 声明(严格说是简化版 DTD)简单的配置文件验证(不值得写 XSD 的场景)新项目用 XSD,没有理由选 DTD。如果嫌 XSD 太啰嗦,可以考虑 RelaxNG——更简洁的替代方案。
计算机基础阅读 925月27日 01:11

GET 和 POST 的区别是什么?何时使用 POST?

从 HTTP 协议本身看,GET 和 POST 只有两个本质区别:语义不同:GET 是"获取"(安全、幂等),POST 是"提交数据以处理"(不幂等)POST 有 body,GET 没有(GET 也可以有 body,但 RFC 不推荐,很多实现不支持)其他所谓的区别——"GET 参数在 URL 里,POST 在 body 里"、"GET 参数长度有限制"、"GET 被浏览器缓存"——要么是实现细节,要么是浏览器的行为,不是协议本身的约束。何时用 POST:创建/修改资源、提交表单、需要传大量数据、需要隐藏敏感参数(虽然 body 也不安全,HTTPS 才是真正保护)。追问GET 请求真的不能有 body 吗?RFC 7231 没有禁止,但建议不要给 GET 加 body。实际上 fetch 和 XMLHttpRequest 都支持带 body 的 GET,但浏览器 <form> 和 <a> 不支持,很多中间件/代理也不处理 GET body。PUT 和 POST 有什么区别?都是提交数据,但语义不同:PUT 是幂等的(多次调用结果相同——替换指定位置的资源),POST 不是(多次调用可能创建多个资源)。PUT 的 URL 通常确定具体资源(/users/1),POST 是集合 URL(/users)。POST 比 GET 更安全吗?不安全。POST body 在 HTTP 下仍然是明文传输,只是 URL 里看不到而已。HTTPS 下二者都加密后才发送,POST 的"安全性"优势在 HTTPS 下不存在。真正的区别是 POST 数据不会出现在日志/浏览器历史/server log 的 URL 中。
计算机基础阅读 1145月27日 01:10

HTTP 有哪些常用的状态码?

按分类记:2xx 成功:200 OK:请求成功201 Created:创建资源成功(POST 返回)204 No Content:成功但无响应体(DELETE 后常见)3xx 重定向:301 Moved Permanently:永久重定向(浏览器会缓存,下次直接跳)302 Found:临时重定向304 Not Modified:资源未修改,用缓存(配合 If-Modified-Since/ETag)307/308:和 301/302 类似,但 POST 转 GET 行为不同4xx 客户端错误:400 Bad Request:请求格式错误401 Unauthorized:未认证403 Forbidden:已认证但无权限404 Not Found:资源不存在405 Method Not Allowed:方法不对(比如用 GET 调了 POST 接口)429 Too Many Requests:被限流5xx 服务端错误:500 Internal Server Error:服务端内部错误502 Bad Gateway:网关/代理收到无效上游响应503 Service Unavailable:服务暂不可用(维护/过载)504 Gateway Timeout:网关超时追问301 和 302 的区别?301 是永久的——浏览器会缓存重定向目标,之后相同 URL 直接跳转,不用再请求原地址。SEO 权重转移。302 是临时的——每次都会请求原地址再跳转。语义不同,对 SEO 和缓存影响很大。401 和 403 怎么区分?401 是"你是谁?"——没登录或 token 过期,需要你去认证。403 是"我知道你是谁,但不让你看"——认证通过了但权限不够。502 和 504 的区别?502 是网关从上游收到了无效/不完整的响应(服务崩溃、配置错误)。504 是网关在规定时间内没等到上游响应(超时)。排查方向:502 看服务有没有挂,504 看服务是不是太慢。
计算机基础阅读 435月27日 01:10

什么是对称加密和非对称加密?

对称加密:加密和解密用同一把密钥。快,适合加密大量数据。问题是怎么安全地把密钥传给对方——密钥传输过程中可能被截获。代表:AES、DES、ChaCha20。非对称加密:一对密钥——公钥加密、私钥解密。公钥可以公开,任何人用公钥加密,只有持有私钥的人能解密。解决了对称加密的密钥分发问题,但计算慢,不适合大数据。代表:RSA、ECC。实际应用中二者组合:用非对称加密传递对称密钥,之后的通信全部用对称加密。HTTPS 的 TLS 握手就是这样干的——RSA/ECDHE 交换密钥 → AES 加密通信内容。追问HTTPS 用的是对称还是非对称?都用。TLS 握手阶段用非对称(RSA/ECDHE)协商出一个对称密钥(Session Key),之后的数据传输用这个对称密钥做 AES 加密。取长补短。为什么非对称加密更安全但更慢?非对称加密的数学基础是大数分解(RSA)或椭圆曲线(ECC),运算量远大于 AES 的位运算。RSA 2048 位密钥加密几百字节就要几十毫秒,AES 加密几 MB 数据只要微秒级。前端的 crypto.subtle 能做非对称加密吗?能。crypto.subtle.generateKey 支持 RSA-OAEP 和 ECDH。但大部分场景 JD 不需要在前端做非对称加密——前端代码公开,私钥无处存放。通常前端只是用 HTTPS 加密传输,非对称部分在 TLS 层自动完成。
计算机基础阅读 525月27日 00:59

发布订阅者模式和观察者模式的区别是什么?

观察者模式是主题直接通知观察者,发布订阅模式是通过消息代理中转。这是两者最根本的区别。打个比方:观察者模式像是你直接打电话通知朋友"我搬家了"——你得知道每个人的号码。发布订阅模式像是你在朋友圈发了一条动态——你不需要知道谁在看,想看的人自然会收到推送。代码层面,观察者模式里 Subject 维护一个 Observer 列表,状态变化时逐个调用 observer.update()。发布订阅模式多了一层 EventBus,publisher.emit(event) 和 subscriber.on(event) 互相不知道对方存在。追问为什么说观察者模式是同步的,发布订阅是异步的?不是绝对的,但典型实现确实如此。观察者模式里 Subject.notify() 直接遍历调用回调,默认同步执行。发布订阅的 EventBus 可以把回调放进微任务队列或 setTimeout,天然支持异步。不过你也可以让观察者异步回调,只是设计意图不同。实际项目中分别用在什么场景?观察者模式:Vue 的响应式系统(Dep → Watcher)、React 的 useState 通知、MobX 的 observer发布订阅:Vue 的 emit/on 事件总线、Node.js EventEmitter、Redis Pub/Sub、消息队列两者可以互相替代吗?简单场景可以用观察者替代发布订阅——比如小项目里直接用 Vue 的 emit 就够。但跨组件、跨模块、甚至跨服务的通信,发布订阅的消息代理解耦优势会很明显。反过来,如果只是两个对象的联动,多加一层 EventBus 反而过度设计了。在面试中应该怎么回答这个区别?先一句话说本质区别(是否经过中介),再用一个比喻让人秒懂,最后补充代码层面的差异(是否有 EventBus、是否知道对方存在)。加分项是举一个真实项目的例子,比如"我们在 XX 项目中用 EventEmitter 解耦了 A 模块和 B 模块的通信"。
计算机基础阅读 865月27日 00:54

HTTPS 和 HTTP 的缓存有什么区别?

HTTPS 和 HTTP 在缓存机制上没有本质区别,缓存规则(Cache-Control、ETag、Expires)在两种协议下都生效。关键差异在安全性导致的行为不同。浏览器对 HTTPS 内容的缓存更谨慎——不会把 HTTPS 资源缓存到磁盘(除非服务端明确允许),隐私模式下 HTTPS 缓存行为也更保守。代理服务器(CDN、中间代理)对 HTTPS 内容无法解密查看,只能根据 URL 和响应头做缓存决策,不能像 HTTP 那样分析内容。HTTPS 的缓存键可以用 Vary 响应头控制。共用缓存(shared cache)场景下,HTTPS 加解密有性能开销,建议配合 CDN 在边缘节点缓存静态资源,减少回源。追问为什么中间代理缓存不了 HTTPS 内容?HTTPS 端到端加密,中间代理看不到内容,只能根据 URL 缓存。所以 HTTPS 更依赖 CDN(CDN 持有证书可以解密后缓存)。HTTPS 对缓存性能有影响吗?加解密有 CPU 开销,但现代硬件都支持硬件加速(AES-NI),影响很小。真正影响首屏的是 TLS 握手多一次 RTT,用 HTTP/2 或 HTTP/3 可以缓解。浏览器对 HTTPS 和 HTTP 缓存策略有什么不同?HTTPS 资源默认不会缓存到磁盘(隐私考虑),HTTP 资源会。如果希望 HTTPS 也磁盘缓存,服务端设 Cache-Control: public。
计算机基础阅读 02月21日 16:17

ASCII 和 Unicode 的主要区别是什么

ASCII 和 Unicode 的主要区别:1. 编码范围:ASCII:使用 7 位二进制,可表示 128 个字符Unicode:使用 16 位或更多位,可表示 1,114,112 个字符2. 字符覆盖:ASCII:仅包含英文字母、数字、基本符号和控制字符Unicode:包含世界上所有语言的字符、符号、表情符号等3. 存储空间:ASCII:每个字符固定 1 字节Unicode:UTF-8 编码下,英文字符 1 字节,中文字符 3 字节Unicode:UTF-16 编码下,常用字符 2 字节,辅助字符 4 字节4. 兼容性:ASCII 是 Unicode 的子集,前 128 个字符完全相同Unicode 向下兼容 ASCII5. 应用场景:ASCII:适用于纯英文文本、简单的网络协议Unicode:适用于国际化应用、多语言支持、现代软件开发选择建议:仅处理英文数据:ASCII 足够需要支持多语言:必须使用 Unicode现代开发环境:推荐使用 Unicode(UTF-8)
计算机基础阅读 1222024年8月5日 12:53

UDP 和 TCP 有什么区别?

TCP(传输控制协议)和UDP(用户数据报协议)都是互联网协议套件中的传输层协议,它们在网络中传输数据有着本质的区别:连接性:TCP 是面向连接的协议。在数据传输之前,它需要建立连接。一个TCP连接需要经过三次握手过程,确保双方准备好进行数据传输。UDP 是无连接的协议。它不需要预先建立连接,数据可以直接发送给接收方,不必等待建立连接。可靠性:TCP 提供可靠的数据传输服务。通过序列号、确认应答、重传控制、流量控制和拥塞控制等机制,确保数据的正确性和顺序性。UDP 不保证数据的可靠传输。它发送的数据包可能会丢失或者顺序错乱,且没有内建的机制来纠正这些错误。速度和效率:TCP 由于其确保数据准确性和顺序性的机制,通常比UDP慢。这些机制使TCP非常可靠,但也增加了通信的开销。UDP 由于缺少复杂的控制机制,能够提供更快的数据传输速度,适用于对实时性要求高的应用,如视频会议和在线游戏。数据流:TCP 提供字节流服务。通过TCP连接发送的数据是按照字节流方式进行传输的,接收方会按照发送时的顺序来接收数据。UDP 提供数据报服务。每个UDP用户数据报是独立传输的,每个数据报都有明确的边界。头部开销:TCP 的头部开销比UDP大。TCP头部至少20字节,包含许多用于保障可靠传输的信息。UDP 的头部开销小,仅有8字节,适合传输小量数据。用例示例:TCP 的典型应用包括Web浏览(HTTP/HTTPS)、电子邮件(SMTP/POP/IMAP)和文件传输(FTP)等,这些应用都需要数据的准确传输。UDP 常用于流媒体传输(如视频和音频流)、在线游戏、语音通话(VoIP)等,这些应用更注重速度而非每个数据包的完整性。总结来说,TCP和UDP各有优缺点,适用于不同的网络应用场景。TCP通过复杂的机制保证数据的可靠性,适合需要高可靠性的应用。UDP则因其低延迟特性,适用于需要快速数据传输但可以容忍一定数据丢失的应用。
计算机基础阅读 972024年8月5日 12:52

什么是A/B测试?

A/B测试,也称为拆分测试,是一种统计学方法,用于比较两个或多个变体,以确定哪个变体在特定性能指标上表现得更好。在A/B测试中,A通常是当前使用的版本(控制组),而B则是改变了某些变量的版本(实验组)。通过将样本随机分配到A组和B组,并对结果进行分析来决定哪个版本更优。例如,在网页设计中,如果想测试一个新的按钮颜色是否会提高用户的点击率,那么可以创建两个版本的网页:一个是带有原始颜色按钮的A版本(控制组),另一个是带有新颜色按钮的B版本(实验组)。然后,将访问者随机分配到两个版本中的一个,并跟踪每个组的点击率。通过统计分析可以判断哪个按钮颜色能够带来更高的点击率。A/B测试的优点在于其简单性和高效性,能够直接对照比较,从而使决策者能够基于实际数据做出更加明智的选择。此外,A/B测试还有助于减少变化带来的风险,因为它允许在较小的用户群中测试改变,而不是全部用户。如果B版本效果更好,则可以将其推广到所有用户;如果效果更差或没有显著差异,则可以保持A版本,或者尝试其他变体进行进一步的测试。
计算机基础阅读 1152024年8月5日 12:51

HTTP 协议 1.0 和 1.1 和 2.0 有什么区别?

HTTP(超文本传输协议)是 Web 上交换数据的基础协议,随着 Web 技术的发展,HTTP 也经历了多个版本的迭代。下面我会详细介绍 HTTP 1.0、1.1 和 2.0 这三个版本的区别:HTTP 1.0无状态连接:HTTP 1.0 是无状态的,也就是说每次请求都需要建立一个新的TCP连接,完成数据传输后连接就会关闭。这种方式在每次请求都需要经历 TCP 连接的建立和断开过程,导致性能上的不足。限制性能:由于每次请求都要建立新的连接,所以并发多个请求会导致大量的延迟和性能问题。无宿主名(Host)字段:HTTP 1.0 不支持 Host 头部。这意味着同一个物理服务器上无法托管多个域名的网站。HTTP 1.1持久连接:HTTP 1.1 默认采用持久连接(也称为“keep-alive”),允许在一个TCP连接上发送和接收多个HTTP请求/响应,从而减少了TCP连接的开销。管线化:HTTP 1.1 引入了请求的管线化,理论上客户端可以在收到前一个响应之前发送下一个请求,减少了请求的延迟。但实际上,由于某些浏览器和服务器的实现问题,这个特性并未广泛使用。新增头部字段:例如 Host(它允许在同一物理服务器上虚拟托管多个域名)、Etag(实体标签,可以协助缓存验证)、Accept-Encoding(指定客户端可以接收的内容编码类型)等。缓存控制:更复杂和灵活的缓存控制机制,使得客户端和服务器可以更有效地协商数据的缓存,减少不必要的数据传输。分块传输编码:允许服务器开始发送响应而不需要先知道全部内容的总大小。HTTP 2.0二进制协议:HTTP/1.x 是文本协议,而 HTTP/2 是二进制协议,提供了更高效的解析和网络传输。多路复用:在同一个连接上并行交错地发送多个请求和响应,而不会互相影响,极大地提高了传输效率和减少了延迟。流优先级:可以为 HTTP/2 连接上的流设置优先级,允许更重要的资源先被发送。服务器推送:服务器可以对一个客户端请求发送多个响应,允许服务器主动推送资源给客户端,进一步提升页面加载效率。头部压缩:HTTP/2 引入了 HPACK 压缩格式,用于减小头部大小,以减少传输延迟。举例来说,一个明显的性能改进是在使用HTTP/2时浏览一个网站:由于多路复用和头部压缩等特性,相比于 HTTP/1.1,网页的加载时间可以显著减少,尤其是在网络条件较差或加载资源较多的场景下。此外,HTTP/2 的服务器推送功能允许服务器预先推送静态资源,比如 CSS 或 JavaScript 文件,这可以进一步提高加载速度,因为浏览器不必等待解析 HTML 再去请求这些资源。
计算机基础阅读 842024年7月4日 09:35

基于 javascript 如何实现队列

队列是一种先进先出(FIFO)的数据结构。在 JavaScript 中,可以使用数组来实现队列的各种操作。以下是一个简单的队列实现的例子,包括入队(enqueue)、出队(dequeue)、查看队首元素(peek)、检查队列是否为空(isEmpty)以及获取队列的大小(size): class Queue { constructor() { this.items = []; // 使用数组存储队列中的元素 } // 入队操作 enqueue(element) { this.items.push(element); } // 出队操作 dequeue() { if (this.isEmpty()) { return '队列为空'; } return this.items.shift(); } // 查看队首元素 peek() { if (this.isEmpty()) { return '队列为空'; } return this.items[0]; } // 检查队列是否为空 isEmpty() { return this.items.length === 0; } // 获取队列的大小 size() { return this.items.length; }}// 使用例子const queue = new Queue();queue.enqueue('John');queue.enqueue('Jack');console.log(queue.peek()); // 输出: Johnqueue.dequeue();console.log(queue.peek()); // 输出: Jackconsole.log(queue.isEmpty()); // 输出: falseconsole.log(queue.size()); // 输出: 1在这个例子中,我定义了一个 Queue 类,它有几个方法来模拟队列的行为。enqueue 方法用于向队列添加一个新元素,dequeue 方法移除队首的元素,peek 方法返回队首元素但不移除它,isEmpty 方法检查队列是否为空,而 size 方法返回队列的当前元素数量。这个实现是使用数组的方法,尽可能地模拟了一个队列的典型操作。
计算机基础阅读 1232024年6月24日 16:43

WebSocket和HTTP协议有什么区别?

WebSocket 和 HTTP 都是网络协议,它们在 Web 应用中承担着数据交换的角色,但是它们在设计上有着根本的差别,满足不同的应用场景。HTTP 协议HTTP(HyperText Transfer Protocol)是一种无状态的请求/响应协议,通常用于客户端和服务器之间的传统网页数据传输。它在 1991 年被发明,用来在互联网上传输超文本(HTML 文档),并随着时间进化到现在的 HTTP/1.1 和 HTTP/2 版本。特点:无状态: 每次请求之间相互独立,服务器不保存之前的请求信息。请求/响应模式: 客户端发送请求,服务器响应该请求,完成一次交互。短连接: 传统的 HTTP/1.1 协议在每次请求完成后都会关闭连接(虽然现在有持久连接的选项Connection: keep-alive)。不双向: 客户端发起请求,服务器响应,服务器不能主动向客户端发送消息。例子:一个典型的 HTTP 交互场景是,用户在浏览器中点击一个链接,浏览器发送一个 HTTP GET 请求到服务器,服务器处理请求并返回一个 HTML 页面,浏览器接收并显示给用户。WebSocket 协议WebSocket 是一个相对较新的协议,它在 2011 年成为国际标准。WebSocket 协议旨在通过单个长期连接提供全双工通信渠道,以支持实时和双向交互。特点:全双工: 客户端和服务器都可以随时向对方发送消息,无需等待响应。长连接: 一旦客户端和服务器之间的 WebSocket 连接打开,它将保持打开状态,直到任何一方显式关闭。低延迟: 数据包头部信息少,减少了发送消息的开销,适合需要快速通信的场景。例子:在一个实时聊天应用中,服务器可以在接收到一条新消息时立即将其推送给所有连接的客户端,而客户端也可以随时发送消息给服务器。所有这些通信都是在同一个 WebSocket 连接上完成的,并且可以非常迅速地进行。总结总得来说,WebSocket 通常用于需要服务器和客户端进行实时、双向和交互式通信的应用(如在线游戏、实时聊天室和协作工具),而 HTTP 更适合于传统的请求/响应模式的应用,比如网页浏览等。WebSocket 与 HTTP 的主要区别在于其持久的连接和低延迟的通信能力。虽然它们可以在相同的端口上运行(WebSocket 常常在 HTTP 的基础上握手建立连接,然后升级到 WebSocket 协议),但它们的设计目标和优化点大相径庭。
计算机基础阅读 932024年6月24日 16:43

谈一谈 HTTP 是如何数据传输

HTTP (HyperText Transfer Protocol) 是用于分布式、协作式、超媒体信息系统的应用层协议。它是互联网上数据通信的基础。其数据传输流程大致如下:建立连接:客户端到服务器的连接:当用户通过浏览器或应用程序请求一个网页时,浏览器首先需要与服务器建立连接。在HTTP/1.1协议中,每次请求通常都会创建一个新的TCP连接,而在HTTP/2中,多个请求可以在同一个连接上复用。发送请求:组建HTTP请求:客户端(如浏览器)会创建一个HTTP请求消息,这个消息包括请求行(包括请求方法如GET或POST,请求的资源路径,以及HTTP版本),请求头部(包括各种元数据如Accept, User-Agent, Host等),以及请求正文(通常在POST请求中携带数据)。发送请求到服务器:客户端将这个请求通过TCP连接发送给服务器。服务器处理请求:服务器解析请求:服务器接收请求消息,并解析请求行和头部,确定请求的资源和操作。处理请求:服务器根据请求类型,调用相关的服务或脚本,如数据库查询、文件读取等,来处理这个请求。发送响应:组建HTTP响应:服务器处理完请求后,会创建一个HTTP响应消息,包括状态行(HTTP版本,状态码,状态文本),响应头部(包括内容类型、内容长度、缓存控制等元数据)和响应正文(请求的资源内容)。发送响应到客户端:服务器通过TCP连接将响应消息发送回客户端。客户端接收响应:解析响应:客户端收到响应后,会解析状态码以了解请求是否成功,以及如何处理返回的数据。显示内容:如果是网页请求,浏览器会解析响应正文中的HTML、CSS和JavaScript内容,并在屏幕上渲染显示网页。关闭连接:断开连接:在HTTP/1.0中,通常每个请求/响应之后连接即关闭。而在HTTP/1.1中,引入了持久连接(keep-alive),允许在一个连接上发送、接收多个请求/响应。不过,最终这个连接也会在一定时间后或按照客户端或服务器的需求被关闭。例子:假设您在浏览器的地址栏输入了一个URL http://example.com 并按下了回车键:建立连接:浏览器通过DNS解析获得 example.com的IP地址,然后向这个地址的80端口发起TCP连接(HTTP默认端口)。发送请求:浏览器构建一个GET请求消息,请求行为 GET / HTTP/1.1,请求头部包含了浏览器类型、接受的内容类型等。服务器处理请求:example.com的服务器接收请求,解析路径 /,找到首页的内容。发送响应:服务器构建响应消息,状态行可能为 HTTP/1.1 200 OK,响应头部包含内容类型为 text/html,然后是响应正文,即HTML内容。客户端接收响应:浏览器接收到响应,解析HTML内容,并在屏幕上渲染出来。关闭连接:如果没有更多的请求,或服务器/客户端决定关闭连接,TCP连接将被关闭。
计算机基础阅读 932024年6月24日 16:43

基于 HTTP 网络层,前端能可以做哪些性能优化?

基于HTTP网络层的前端性能优化主要关注的是资源的加载和传输效率。以下是一些前端可以采取的性能优化措施:1. 减少HTTP请求次数合并文件:将多个CSS或JavaScript文件合并成单个文件以减少请求数量。精灵图(Sprite Maps):将多个小图标合并到一张图片中,通过CSS背景定位显示所需图标。内联图片(Data URIs):将小图像直接内嵌到HTML或CSS中,减少图片请求。2. 使用CDN(内容分发网络)分布式节点:CDN将静态资源缓存在全球的多个节点,使用户能从就近的服务器下载,降低延迟。缓存效率:CDN通常会对资源进行优化缓存,提高再次访问的速度。3. 缓存优化强缓存:通过设置HTTP头中的Cache-Control和Expires标识,使资源在客户端本地缓存,直到缓存过期。协商缓存:利用ETag和Last-Modified标识,仅当资源更新时才重新下载。4. 延迟加载和按需加载懒加载:对于非首屏图片、视频等资源进行懒加载,即滚动到可视区域后才加载。代码分割(Code Splitting):通过工具如Webpack实现模块的按需加载,避免单页应用加载过多不必要的JavaScript代码。5. 优化请求头和响应头压缩请求头:减少Cookie的大小和使用的数量,以及其他不必要的HTTP头部信息。Gzip/Brotli压缩:对文本资源进行Gzip或Brotli压缩,减少传输大小。6. HTTP/2和HTTP/3的使用多路复用:HTTP/2允许在同一个连接上并行传输多个请求响应,消除了队头阻塞问题。服务器推送:HTTP/2的Server Push可以提前发送资源,减少等待时间。QUIC协议:HTTP/3使用QUIC协议,减少连接建立时间,提升传输效率。7. 优化TLS/SSL握手TLS 1.3:使用更新的TLS版本可以减少握手过程中的往返次数。OCSP Stapling:通过服务器代替客户端查询证书状态,减少TLS握手的延迟。8. 优化资源的加载顺序关键请求优先:确保关键资源(如HTML、CSS、关键JavaScript函数)最先加载。异步加载:使用async和defer属性对非关键JavaScript脚本进行异步加载。9. WebP格式使用WebP:相比传统的JPEG或PNG格式,WebP格式在同等质量下具有更小的文件大小。10. Service Workers离线体验:Service Workers可以帮助缓存资源,并在无网络状态下提供访问。背景同步:Service Workers可以在后台进行数据同步或推送通知。举例来说,对于一个电商网站,我之前优化过的一个项目中,通过使用图片懒加载和WebP格式,网站首页的加载时间减少了约30%。利用HTTP/2的多路复用特性,也显著提高了资源加载的并行度,进一步减少了页面的完
计算机基础阅读 512024年6月24日 16:43

为什么二叉树很重要,而不是三叉树四叉树

二叉树在数据结构与算法中是极其重要的,原因有几个方面:结构简单明了:二叉树的结构相对简单,每个节点最多有两个子节点。这种结构易于理解和实现,同时也方便了各种算法在其上的操作,比如遍历、插入、删除等。效率平衡:二叉树,在特定情况下如二叉搜索树(BST),可以保持数据的有序性,同时插入、删除、查找操作的平均时间复杂度为O(log n),这是因为每进行一次操作,搜索范围就缩小一半。对于三叉树或四叉树,虽然可能在某些情况下查找更快,但它们的维护(如重新平衡)成本可能会更高。便于算法优化:二叉树的结构特性使得很多算法可以高效运行,比如在二叉搜索树中可以非常快速地进行查找、插入和删除操作。另外,二叉树还可以优化为平衡树(如AVL树)和红黑树,这些结构能够保持树的平衡,进一步确保操作效率。实用性:在实际应用中,二叉树已经足够应对大多数情况,例如二叉搜索树、堆(用于实现优先队列)以及Huffman编码树等,都是基于二叉树结构的。这些结构已经广泛地应用在各个领域,比如数据库索引、内存分配策略、压缩算法等。递归和分治算法:二叉树的递归特性非常适合采用递归或分治算法来解决问题。二分的思想可以很自然地应用在二叉树上,而三叉或四叉树的分割就不那么直观和简洁。举个例子,比如在二叉搜索树中查找一个元素,我们可以从根节点开始,如果查找的元素小于当前节点的值,就转向左子树进行查找;如果大于当前节点的值,就转向右子树进行查找,这样每次都可以排除掉半边的树,使得查找非常高效。相比之下,在三叉或四叉树中,虽然每次也能排除一部分树,但实际上,由于节点的孩子增多,树的高度减小的速度并不一定能够保持在对数级别,同时节点管理也更加复杂。综上所述,二叉树因其简单性、效率、以及在实践中的广泛应用,成为了数据结构中的重要组成部分。而三叉树、四叉树虽然在某些方面可能有其优点,但在大多数情况下,它们并不提供足够的性能优势来证明它们比二叉树更有用或更为关键。
计算机基础阅读 352024年6月24日 16:43

实现二分查找并分析时间复杂度

实现二分查找def binary_search(arr, target): left, right = 0, len(arr) - 1 while left <= right: mid = left + (right - left) // 2 if arr[mid] == target: return mid elif arr[mid] < target: left = mid + 1 else: right = mid - 1 return -1分析时间复杂度二分查找算法的时间复杂度是 O(log n)。下面我将解释为什么是这样的。二分查找算法的基本思想是在一个有序数组中不断地将搜索区间减半。具体来说,算法从数组的中间元素开始,如果中间元素正好是目标值,则搜索结束;如果目标值大于中间元素,则在数组的右半部分继续搜索;如果目标值小于中间元素,则在数组的左半部分继续搜索。每次比较都会将搜索区间减半,因此我们可以说在最坏的情况下(即目标值不在数组中或者在数组的末端),算法需要执行的步骤数与数组长度 n 的对数成正比。这是因为每次操作减少一半的搜索空间,那么经过 k 次操作后,数组的大小将是原来的 1/2^k。要找出 k,我们设置 n/(2^k) = 1,并解出 k。通过对数运算,我们得到 k = log2(n)。因此算法的时间复杂度是 O(log n)。举例来说,假设我们有一个包含 1 到 1024(包含)的数组,我们要查找数字 1024。二分查找会经历以下步骤:比较中间的数(大约 512),1024 大于它,因此我们去右边的子数组里查找。再取右子数组的中间数(大约 768),1024 仍然大于它,再次去右边的子数组里查找。这样的过程会持续进行,每次我们都排除了一半的数字,直到最后找到 1024。在这个例子中,1024 是2的10次幂,所以我们需要10步来找到正确的数字,这符合我们的 O(log n) 时间复杂度分析。