目录
一、数据结构算法等综合篇
1.直接插入排序,有n个元素待排序,则最多进行多少次比较
2.软件测试中评估网络性能的关键指标有哪些
3.哈希查找
4.内存保护
二、代码输出篇
1.promise中throw new Error输出
2.Promise.all
3.this关键字,obj.get()()
4.typeof判断匿名函数的function后的test和test()类型
三、css、html篇
1.父盒子设置为flex后,子元素设置哪个属性不会失效?
2.link和@import
一、数据结构算法等综合篇
1.直接插入排序,有n个元素待排序,则最多进行多少次比较
答案:(n-1) * n / 2
直接插入排序(也称为简单插入排序)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
第2个元素需要与前面的1个元素进行比较。第3个元素需要与前面的2个元素进行比较。依此类推,直到第n个元素,它需要与前面的n-1个元素进行比较(但实际上,在找到插入位置后,后续的比较可能会提前终止,因为一旦找到比当前元素大的元素,就可以确定插入位置了)。
- 为了计算最多比较次数,我们不考虑提前终止的情况,而是假设每次都需要与前面的所有元素进行比较。
- 因此,最多比较次数为1 + 2 + 3 + ... + (n-1)。其和为(n-1) * n / 2
2.软件测试中评估网络性能的关键指标有哪些
吞吐量 并发数 响应时间 带宽 时延 丢包率 错误率 资源利用率
3.哈希查找
哈希查找是一种通过计算数据元素的存储地址进行查找的方法。以下是对哈希查找的详细解释:
一、定义与原理
哈希查找基于哈希函数,该函数将关键字映射为数组中的索引。这样,通过计算要查找的关键字的哈希值,可以直接定位到数组中的相应位置,从而大大减少了查找次数。如果哈希函数设计得当,且内存空间足够,那么查找一个数据元素所需的比较次数基本上就接近于一次。
二、操作步骤
哈希查找通常包括以下三个步骤:
-
计算哈希值:将待查找的关键字通过哈希函数转换为哈希值。
-
定位地址:利用哈希值在哈希表中定位到相应的存储位置。
-
比较与查找:在定位到的存储位置中,通过比较找到与待查找关键字相同的元素(如果存在)。
三、哈希函数的构造
哈希函数的构造是哈希查找的关键。常见的哈希函数构造方法包括:
-
直接定址法:取关键字的某个线性函数值为哈希地址,即H(key)=a*key+b,其中a和b为常数。
-
数字分析法:分析一组关键字,从中提取分布均匀的若干位作为哈希地址。
-
平方取中法:取关键字的平方值的中间几位作为哈希地址。
-
折叠法:将关键字分割成位数相同的几部分,然后取这几部分的叠加和(舍去进位)作为哈希地址。
-
除留余数法:取关键字被某个不大于哈希表表长m的数p除后所得的余数为哈希地址,即H(key)=key%p。
-
随机数法:选择一个随机函数,取关键字的随机函数值为哈希地址,即H(key)=random(key)。
四、冲突解决
在哈希查找中,可能会出现多个关键字映射到同一个哈希地址的情况,这称为哈希冲突。解决哈希冲突的方法主要有两种:
-
开放地址法:当发生冲突时,寻找下一个空的哈希地址来存储该元素。常用的开放地址法有线性探测法、二次探测法和双重散列法等。
-
链地址法:将具有相同哈希地址的元素存储在一个链表中。这样,即使出现冲突,也只需要在相应的链表中进行查找即可。
五、优缺点
哈希查找具有以下优点:
-
查找效率高:在哈希表中查找元素的时间复杂度为O(1),即查找时间与数据集合的大小无关。
-
空间利用率高:哈希查找只需要存储关键字和对应的值,不需要额外的空间来存储指针等信息。
-
可扩展性强:可以通过调整哈希函数和哈希表的大小来适应不同的数据集合。
然而,哈希查找也存在一些缺点:
-
哈希冲突:如果哈希函数设计不当或哈希表过小,可能会导致哈希冲突频繁发生,从而降低查找效率。
-
哈希函数设计困难:设计一个好的哈希函数并不容易,需要综合考虑关键字的长度、分布情况、哈希表长度等因素。
-
不支持范围查找:哈希查找只能支持精确查找,无法支持范围查找。
-
删除操作困难:在链地址法中,删除一个元素可能需要遍历链表并更新哈希表的指针;在开放地址法中,删除元素后可能需要处理空洞问题。
综上所述,哈希查找是一种高效的查找方法,但需要注意哈希函数的设计和冲突解决策略的选择。在实际应用中,需要根据具体需求和数据特点选择合适的哈希查找算法和参数设置。
4.内存保护
内存保护是操作系统和计算机硬件对内存进行访问权限管理的一种机制。以下是关于内存保护的详细解释:
一、内存保护的目的
内存保护的主要目的是防止某个进程或程序访问未被操作系统配置给它的内存空间。这可以确保每个进程都有一个独立的内存空间,防止程序错误或恶意行为对其他进程或操作系统本身造成影响。
二、内存保护的实现方式
-
硬件实现:
-
内存保护单元(MPU):MPU是计算机硬件中的一个单元,通常由CPU提供,用于实现内存保护。它将内存划分为多个具有不同访问权限的区域,并允许特权软件定义这些区域及其访问规则。
-
寄存器保护:在CPU中设置上、下限寄存器或重定位寄存器和界地址寄存器,用于存放用户作业在主存中的地址范围。当CPU访问内存时,会检查访问地址是否在这些寄存器定义的范围内,从而防止越界访问。
-
-
软件实现:
-
操作系统管理:操作系统负责分配和管理内存空间,确保每个进程只能访问其被分配的内存区域。当进程尝试访问未分配或受保护的内存时,操作系统会阻止这种访问并可能产生错误报告。
-
内存保护技术:现代操作系统和编译器使用多种内存保护技术来增加攻击的难度,保护系统免受常见类型的攻击。这些技术包括ASLR(地址空间布局随机化)、DEP/NX(数据执行预防/不执行)、Canaries(缓冲区溢出检测技术)、PIE(位置无关可执行文件)等。
-
三、内存保护的应用场景
-
防止程序错误:内存保护可以防止程序因访问未分配的内存或越界访问而导致的错误,从而提高程序的稳定性和可靠性。
-
保护敏感数据:通过为敏感数据分配受保护的内存区域,内存保护可以防止这些数据被未经授权的访问或修改,从而保护数据的机密性和完整性。
-
增强系统安全性:内存保护机制可以防止恶意程序利用内存漏洞进行攻击,从而增强系统的安全性。例如,通过阻止程序在标记为非执行的内存区域中执行代码,可以防止缓冲区溢出攻击。
四、内存保护的实例
在实际应用中,内存保护机制被广泛应用于各种操作系统和计算机硬件中。例如,在Linux操作系统中,内存保护机制通过页表、内存段和访问控制列表等结构来实现。而在某些嵌入式系统中,MPU被用于实现内存保护,以确保系统的稳定性和安全性。
此外,还有一些专门的内存保护软件,如MemGuard等,它们通过在内存中加密和保护数据来提高敏感信息的安全性。这些软件通常使用先进的加密算法和安全策略来防止数据泄露和攻击。
综上所述,内存保护是计算机系统和操作系统中不可或缺的一部分。它通过各种硬件和软件机制来实现对内存空间的访问控制和管理,从而确保系统的稳定性和安全性。
二、代码输出篇
1.promise中throw new Error输出
Promise.resolve().then(()=>{
throw new Error('err')
}).then((data)=>{
console.info('then:',data)
}).catch((err)=>{
console.info('catch:',err)
})
输出结果为 catch: Error: err
上面的代码使用了 JavaScript 的 Promise 对象来处理异步操作。让我们逐步分析代码的执行流程:
-
Promise.resolve()
创建一个已经解决的(fulfilled)Promise 对象。 -
.then(()=>{ throw new Error('err') })
是在 Promise 解决(fulfilled)后执行的第一个.then
回调。在这个回调中,通过throw new Error('err')
抛出了一个错误。 -
当在
.then
回调中抛出错误时,这个错误会被传递给后续的.catch
回调(如果有的话),而不是传递给下一个.then
的成功回调。这是因为 Promise 链中的错误会被“冒泡”传递到最近的.catch
回调。 -
.then((data)=>{ console.info('then:',data) })
是第二个.then
回调,但由于前面的.then
回调中抛出了错误,这个回调不会被执行。 -
.catch((err)=>{ console.info('catch:',err) })
是处理错误的.catch
回调。由于前面的.then
回调抛出了错误,这个.catch
回调会被执行,并且接收到抛出的错误对象。
2.Promise.all
let p1 = new Promise((resolve, reject) => {
resolve(1);
})
let p2 = [];
Promise.all([p1, p2]).then(val => console.log(val)).catch(err => console.log(err))
输出结果为
[1, Array(0)]
在这段代码中,我们首先创建了一个 Promise
对象 p1
,它会在创建时立即解决(resolve)并返回值 1
。然后,我们创建了一个空数组 p2
。
接下来,我们使用 Promise.all
方法来等待一个包含 p1
和 p2
的数组中的所有 Promise
对象都完成。Promise.all
方法接收一个可迭代对象(例如数组),该对象包含多个 Promise
对象,或者可以转换为 Promise
的对象。它返回一个新的 Promise
,该 Promise
在所有给定的 Promise
都成功完成时才会解决,其解决值是一个数组,包含了所有 Promise
的解决值(按相同的顺序)。如果任何一个 Promise
被拒绝(reject),Promise.all
返回的 Promise
会立即被拒绝,并返回那个导致拒绝的 Promise
的拒绝理由。
然而,在这个例子中,p2
是一个普通的数组,而不是一个 Promise
对象。但是,Promise.all
可以处理非 Promise
值,它会将这些值视为已经解决的 Promise
,其解决值就是该值本身。因此,p2
在这里被视为一个已经解决的 Promise
,其解决值为空数组 []
。
所以,当 Promise.all([p1, p2])
执行时,它会等待 p1
和 p2
(作为已经解决的 Promise
)都完成。因为两者都已经“完成”(p1
是解决的 Promise
,p2
被视为解决的 Promise
),所以 Promise.all
返回的 Promise
会立即解决。
最终,then
回调会被调用,其参数 val
是一个数组,包含了 p1
和 p2
的解决值,即 [1, []]
。因此,控制台会输出:[1, Array(0)]
3.this关键字,obj.get()()
let name="李四"
let obj={
name: "张三",
get:function(item){
return ()=>console.log(this.name)
}
}
obj.get()()
输出结果为 张三
let name = "李四"; // 全局变量
let obj = {
name: "张三",
get: function(item) {
// 这里的 this 指向 obj,因为 get 是 obj 的一个方法
// 但箭头函数不会创建自己的 this 绑定,它会捕获其所在词法作用域的 this
return () => console.log(this.name);
}
};
obj.get()(); // 调用 obj.get() 返回箭头函数,并立即执行该箭头函数
-
obj.get
是一个普通函数,因此当obj.get()
被调用时,其内部的this
指向obj
。 -
obj.get()
返回的是一个箭头函数() => console.log(this.name)
。 - 这个箭头函数是在
obj.get
的词法作用域内定义的,因此它捕获了obj.get
内部的this
值,即obj
。 - 当你执行
obj.get()()
时,实际上是先调用了obj.get()
得到箭头函数,然后立即执行该箭头函数。 - 箭头函数中的
this.name
实际上是指obj.name
,因为箭头函数捕获了obj.get
方法中的this
值。
4.typeof判断匿名函数的function后的test和test()类型
var func=function test(){
console.log(123)
}
console.log(typeof(test))
console.log(typeof(test()))
输出为:
第一行是因为test变量不存在,所以typeof出来的值是undefined,第二行是尝试调用test函数并检查返回值,但是因为test()未定义,所以还没有执行到typeof,所以输出是报错test未定义。
三、css、html篇
1.父盒子设置为flex后,子元素设置哪个属性不会失效?
A.marginB.clearC.vertival-alignD.float
逐一分析:
A. margin:在flex布局中,子元素的margin属性是有效的。您可以设置子元素的外边距来控制其与其他元素之间的距离。
B. clear:在flex布局中,子元素的clear属性将失效。clear属性在传统布局中用于控制浮动元素的旁边不允许有其他浮动元素,但在flex布局中,浮动布局的概念已经不再适用,因此clear属性也就失去了作用。
C. vertical-align:在flex布局中,子元素的vertical-align属性也将失效。vertical-align属性通常用于设置行内元素或表格单元格的垂直对齐方式,但在flex布局中,子元素被视为flex项,其布局方式由flex容器的属性来控制,因此vertical-align属性不再适用。
D. float:同样地,在flex布局中,子元素的float属性也会失效。float属性在传统布局中用于将元素浮动到左侧或右侧,但在flex布局中,元素的排列和布局由flex容器的flex-direction、justify-content、align-items等属性来控制,因此float属性不再适用。
2.link和@import
link
和@import
都是用于在CSS中引入外部样式资源的方法,但它们在使用方式、加载时机、性能以及兼容性等方面存在显著区别。
一、link
标签
-
用法:
-
link
标签是HTML的一部分,通常放在文档的<head>
部分。 -
它使用
href
属性来指定外部CSS文件的路径。 -
例如:
<link rel="stylesheet" href="styles.css">
。
-
-
加载时机:
-
link
标签是异步加载的,即浏览器会继续解析HTML文档,直到遇到link
标签时才开始下载CSS文件。 -
这种方式有利于提高页面的首屏加载速度。
-
-
性能:
-
由于
link
标签是异步加载的,它不会阻塞页面的渲染。 -
在加载失败时,浏览器会继续渲染页面,并显示默认样式或使用内联样式(如果有的话)。
-
-
兼容性:
-
link
标签被所有主流浏览器支持,具有更好的兼容性。
-
二、@import
语法
-
用法:
-
@import
是CSS的一种语法,它允许在CSS文件内部引用另一个CSS文件。 -
它通常放在
<style>
标签内部或另一个CSS文件的顶部。 -
例如:
@import url("styles.css");
。
-
-
加载时机:
-
@import
是在页面加载过程中同步加载的,即浏览器在解析文档时会同步下载并应用对应的CSS文件。 -
这可能会阻塞页面的渲染,尤其是对于大文件,可能导致性能问题。
-
-
性能:
-
由于
@import
是同步加载的,它可能会阻塞页面的渲染,从而影响页面的加载速度。 -
如果
@import
引入的文件不存在或网络请求失败,可能会导致整个文档的样式出现问题。
-
-
兼容性:
-
@import
在一些较旧的浏览器中可能不被完全支持,但在现代浏览器中通常没有问题。
-
三、总结
-
性能与加载时机:
link
标签提供了更好的性能和更友好的用户体验,因为它是异步加载的,不会阻塞页面的渲染。而@import
可能会阻塞页面的渲染,影响性能。 -
兼容性:
link
标签的兼容性更好,几乎支持所有浏览器。而@import
在一些较旧的浏览器中可能不被完全支持。 -
使用场景:
link
标签更适合用于引入外部CSS文件,因为它提供了更好的性能和兼容性。而@import
更适合用于小规模的样式组织或历史遗留项目。
因此,在大多数情况下,建议使用link
标签来引入外部CSS文件。
加油加油^_^