0%

矩阵的特殊存储结构与压缩策略

矩阵是线性代数的核心数据结构,在计算机中通常以二维数组存储。但对于特殊矩阵(如对称矩阵、三对角矩阵)和稀疏矩阵,直接使用二维数组会导致大量空间浪费。因此,针对这些矩阵的特性,需要设计专门的压缩存储方案。

对称矩阵的压缩存储

对称矩阵的核心特性是 A[i][j] = A[j][i](元素关于主对角线对称),因此只需存储主对角线及一侧的元素(通常选择下三角区 + 主对角线),即可完整表示矩阵,空间复杂度从 O(n²) 降至 O(n²/2)

存储规则

设矩阵为 n×n 阶对称矩阵,仅存储满足 i ≥ j(下三角区及主对角线)的元素:

  • 行优先顺序存储,将二维坐标 (i, j) 映射到一维数组 sa[k] 中。
  • 映射公式:
    对于 i ≥ jk = i×(i+1)/2 + j
    (推导:第 0 行存 1 个元素,第 1 行存 2 个元素,…,第 i 行存 i+1 个元素,前 i 行共 i×(i+1)/2 个元素,加上第 i 行的第 j 个元素,总索引为 i×(i+1)/2 + j)。

元素访问

  • i ≥ j 时,直接通过 k = i×(i+1)/2 + j 访问 sa[k]
  • i < j 时,利用对称性 A[i][j] = A[j][i],通过 k = j×(j+1)/2 + i 访问。
阅读全文 »

知识产权知识点

  1. 发表权的保护期受时间限制:终生+死后50年
  2. 修改权、署名权、保护作品完整权的保护期不受限制:永久
  3. 软件著作权产生时间:自作品创作完成之日起
  4. 软件著作权的客体包括:源程序、目标程序、软件文档等
  5. 《中华人民共和国著作权法》和《计算机软件保护条例》是两个基本法律文件
  6. 专利权是谁先申请是谁的
  7. 商标权可以无限延期
  8. 商标注册谁先注册是谁的,同天注册,谁先使用是谁的

数据挖掘算法

分类算法

找出一个类别的概念描述,代表了这个类别数据的整体信息,一般用规则或决策树模式表示。

根据历史数据预测新数据,使用的是分类算法

  • 贝叶斯信念网络(C4.5)

聚类算法

依赖样本间关联的量度标准将其自动分成几个群组,且使同一群组内样本相似,属于不同群组的样本相异

  • K-means
  • EM

关联规则挖掘算法

发现隐藏在数据之间相互关系

  • Apriori

hexo博客next主题使用echarts图表

创建charts.js

在next/scripts/helpers下创建charts.js

1
2
3
4
5
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
const cheerio = require('cheerio')
const moment = require('moment')

hexo.extend.filter.register('after_render:html', function (locals) {
const $ = cheerio.load(locals)
const post = $('#posts-chart')
const tag = $('#tags-chart')
const category = $('#categories-chart')
const htmlEncode = false

if (post.length > 0 || tag.length > 0 || category.length > 0) {
if (post.length > 0 && $('#postsChart').length === 0) {
if (post.attr('data-encode') === 'true') htmlEncode = true
post.after(postsChart(post.attr('data-start')))
}
if (tag.length > 0 && $('#tagsChart').length === 0) {
if (tag.attr('data-encode') === 'true') htmlEncode = true
tag.after(tagsChart(tag.attr('data-length')))
}
if (category.length > 0 && $('#categoriesChart').length === 0) {
if (category.attr('data-encode') === 'true') htmlEncode = true
category.after(categoriesChart(category.attr('data-parent')))
}

if (htmlEncode) {
return $.root().html().replace(/&amp;#/g, '&#')
} else {
return $.root().html()
}
} else {
return locals
}
}, 15)

function postsChart (startMonth) {
const startDate = moment(startMonth || '2020-01')
const endDate = moment()

const monthMap = new Map()
const dayTime = 3600 * 24 * 1000
for (let time = startDate; time <= endDate; time += dayTime) {
const month = moment(time).format('YYYY-MM')
if (!monthMap.has(month)) {
monthMap.set(month, 0)
}
}
hexo.locals.get('posts').forEach(function (post) {
const month = post.date.format('YYYY-MM')
if (monthMap.has(month)) {
monthMap.set(month, monthMap.get(month) + 1)
}
})
const monthArr = JSON.stringify([...monthMap.keys()])
const monthValueArr = JSON.stringify([...monthMap.values()])

return `
<script id="postsChart">
var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
var postsChart = echarts.init(document.getElementById('posts-chart'), 'light');
var postsOption = {
title: {
text: '文章发布统计图',
x: 'center',
textStyle: {
color: color
}
},
tooltip: {
trigger: 'axis'
},
xAxis: {
name: '日期',
type: 'category',
boundaryGap: false,
nameTextStyle: {
color: color
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color
},
axisLine: {
show: true,
lineStyle: {
color: color
}
},
data: ${monthArr}
},
yAxis: {
name: '文章篇数',
type: 'value',
nameTextStyle: {
color: color
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color
},
axisLine: {
show: true,
lineStyle: {
color: color
}
}
},
series: [{
name: '文章篇数',
type: 'line',
smooth: true,
lineStyle: {
width: 0
},
showSymbol: false,
itemStyle: {
opacity: 1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 165)'
},
{
offset: 1,
color: 'rgba(1, 191, 236)'
}])
},
areaStyle: {
opacity: 1,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 165)'
}, {
offset: 1,
color: 'rgba(1, 191, 236)'
}])
},
data: ${monthValueArr},
markLine: {
data: [{
name: '平均值',
type: 'average',
label: {
color: color
}
}]
}
}]
};
postsChart.setOption(postsOption);
window.addEventListener('resize', () => {
postsChart.resize();
});
postsChart.on('click', 'series', (event) => {
if (event.componentType === 'series') window.location.href = '/archives/' + event.name.replace('-', '/');
});
</script>`
}

function tagsChart (len) {
const tagArr = []
hexo.locals.get('tags').map(function (tag) {
tagArr.push({ name: tag.name, value: tag.length, path: tag.path })
})
tagArr.sort((a, b) => { return b.value - a.value })

const dataLength = Math.min(tagArr.length, len) || tagArr.length
const tagNameArr = []
for (let i = 0; i < dataLength; i++) {
tagNameArr.push(tagArr[i].name)
}
const tagNameArrJson = JSON.stringify(tagNameArr)
const tagArrJson = JSON.stringify(tagArr)

return `
<script id="tagsChart">
var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
var tagsChart = echarts.init(document.getElementById('tags-chart'), 'light');
var tagsOption = {
title: {
text: 'Top ${dataLength} 标签统计图',
x: 'center',
textStyle: {
color: color
}
},
tooltip: {},
xAxis: {
name: '标签',
type: 'category',
nameTextStyle: {
color: color
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color,
interval: 0
},
axisLine: {
show: true,
lineStyle: {
color: color
}
},
data: ${tagNameArrJson}
},
yAxis: {
name: '文章篇数',
type: 'value',
splitLine: {
show: false
},
nameTextStyle: {
color: color
},
axisTick: {
show: false
},
axisLabel: {
show: true,
color: color
},
axisLine: {
show: true,
lineStyle: {
color: color
}
}
},
series: [{
name: '文章篇数',
type: 'bar',
data: ${tagArrJson},
itemStyle: {
borderRadius: [5, 5, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 165)'
},
{
offset: 1,
color: 'rgba(1, 191, 236)'
}])
},
emphasis: {
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(128, 255, 195)'
},
{
offset: 1,
color: 'rgba(1, 211, 255)'
}])
}
},
markLine: {
data: [{
name: '平均值',
type: 'average',
label: {
color: color
}
}]
}
}]
};
tagsChart.setOption(tagsOption);
window.addEventListener('resize', () => {
tagsChart.resize();
});
tagsChart.on('click', 'series', (event) => {
if(event.data.path) window.location.href = '/' + event.data.path;
});
</script>`
}

function categoriesChart (dataParent) {
const categoryArr = []
let categoryParentFlag = false
hexo.locals.get('categories').map(function (category) {
if (category.parent) categoryParentFlag = true
categoryArr.push({
name: category.name,
value: category.length,
path: category.path,
id: category._id,
parentId: category.parent || '0'
})
})
categoryParentFlag = categoryParentFlag && dataParent === 'true'
categoryArr.sort((a, b) => { return b.value - a.value })
function translateListToTree (data, parent) {
let tree = []
let temp
data.forEach((item, index) => {
if (data[index].parentId == parent) {
let obj = data[index];
temp = translateListToTree(data, data[index].id);
if (temp.length > 0) {
obj.children = temp
}
if (tree.indexOf())
tree.push(obj)
}
})
return tree
}
const categoryNameJson = JSON.stringify(categoryArr.map(function (category) { return category.name }))
const categoryArrJson = JSON.stringify(categoryArr)
const categoryArrParentJson = JSON.stringify(translateListToTree(categoryArr, '0'))

return `
<script id="categoriesChart">
var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
var categoriesChart = echarts.init(document.getElementById('categories-chart'), 'light');
var categoryParentFlag = ${categoryParentFlag}
var categoriesOption = {
title: {
text: '文章分类统计图',
x: 'center',
textStyle: {
color: color
}
},
legend: {
top: 'bottom',
data: ${categoryNameJson},
textStyle: {
color: color
}
},
tooltip: {
trigger: 'item'
},
series: []
};
categoriesOption.series.push(
categoryParentFlag ?
{
nodeClick :false,
name: '文章篇数',
type: 'sunburst',
radius: ['15%', '90%'],
center: ['50%', '55%'],
sort: 'desc',
data: ${categoryArrParentJson},
itemStyle: {
borderColor: '#fff',
borderWidth: 2,
emphasis: {
focus: 'ancestor',
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(255, 255, 255, 0.5)'
}
}
}
:
{
name: '文章篇数',
type: 'pie',
radius: [30, 80],
roseType: 'area',
label: {
color: color,
formatter: '{b} : {c} ({d}%)'
},
data: ${categoryArrJson},
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(255, 255, 255, 0.5)'
}
}
}
)
categoriesChart.setOption(categoriesOption);
window.addEventListener('resize', () => {
categoriesChart.resize();
});
categoriesChart.on('click', 'series', (event) => {
if(event.data.path) window.location.href = '/' + event.data.path;
});
</script>`
}

添加echarts引用

在next/layout/_layout.swig文件中添加echarts引用(在<title>标签下一行添加)

1
<script src="https://npm.elemecdn.com/echarts@4.9.0/dist/echarts.min.js"></script>

标签页增加标签统计图

在next/layout/page.swig文件中修改。在{%- if page.type === 'tags' %}下一行添加<div id="tags-chart" data-length="10" style="border-radius: 8px; height: 300px; padding: 10px;"></div>

1
2
3
{%- if page.type === 'tags' %}
// 增加内容
<div id="tags-chart" data-length="10" style="border-radius: 8px; height: 300px; padding: 10px;"></div>

分类页增加分类统计图

在next/layout/page.swig文件中修改。在{% elif page.type === 'categories' %}下一行添加<div id="categories-chart" data-parent="true" style="height: 300px; padding: 10px;"></div>

1
2
3
{% elif page.type === 'categories' %}
// 增加内容
<div id="categories-chart" data-parent="true" style="height: 300px; padding: 10px;"></div>

归档页增加归档统计图

在next/layout/archive.swig文件中修改。在<span class="collection-header">{{ __('cheers.' + cheers) }}! {{ _p('counter.archive_posts', site.posts.length) }} {{ __('keep_on') }}</span>下一行添加<div id="posts-chart" data-start="2021-01" style="border-radius: 8px; height: 300px; padding: 10px;"></div>

1
2
3
<span class="collection-header">{{ __('cheers.' + cheers) }}! {{ _p('counter.archive_posts', site.posts.length) }} {{ __('keep_on') }}</span>
// 增加内容
<div id="posts-chart" data-start="2021-01" style="border-radius: 8px; height: 300px; padding: 10px;"></div>

软件过程

能力成熟度模型(CMM)

CMM 是针对软件过程改进的经典模型,核心是通过分级评估推动软件组织的过程从无序到有序、从经验型到量化管理的演进。

  1. 初始级
    • 特点:过程无规范,依赖个人经验,项目成功与否高度取决于团队成员的能力,缺乏可重复性。
    • 典型问题:进度、成本难以控制,质量不稳定,类似 “救火式” 开发。
  2. 可重复级
    • 核心:建立基础的项目管理流程,如计划制定、进度跟踪、成本控制、配置管理等,使成功的项目经验可重复。
    • 关键实践:制定基线(如需求基线、设计基线),进行项目评审,记录并复用过往项目的经验。
  3. 已定义级
    • 核心:将管理和工程过程标准化、文档化,形成组织级的标准过程(如标准开发流程、模板、指南),所有项目均基于此执行。
    • 关键实践:建立组织过程资产库(如过程手册、案例库),对过程进行裁剪以适应不同项目需求。
  4. 已管理级
    • 核心:引入定量管理,对过程和产品质量设定量化指标(如缺陷率、生产率),通过数据监控过程性能。
    • 关键实践:收集过程数据(如开发周期、工作量),使用统计方法分析偏差,确保过程稳定在可接受的量化范围内。
  5. 优化级
    • 核心:通过定量反馈创新改进持续优化过程,主动识别过程中的薄弱环节,引入新技术、新方法提升效率和质量。
    • 关键实践:建立过程改进小组,基于数据分析推动增量式改进,鼓励全员参与创新。

能力成熟度模型集成(CMMI)

CMMI 是在 CMM 基础上发展而来的综合性模型,不仅适用于软件,还覆盖硬件、系统工程等领域,通过 “阶段式” 或 “连续式” 评估框架,更灵活地支持组织的过程改进。

  1. CL0(未完成的)
    • 过程未执行或未达到预期目标,如未定义输入输出、关键活动缺失。
  2. CL1(已执行的)
    • 过程能产生可识别的输出(如代码、文档),但仅满足基本的 “做了”,缺乏系统性管理。
  3. CL2(已管理的)
    • 过程被计划和监控,明确输入、输出和资源,通过管理确保过程按计划执行(如跟踪进度、控制质量)。
    • 与 CMM “可重复级” 类似,但更强调对过程本身的管理而非仅项目管理。
  4. CL3(已定义的)
    • 过程基于组织级的标准和规程,被文档化并制度化,且与组织的业务目标对齐。
    • 相比 CMM 的 “已定义级”,CMMI 更强调过程与组织战略的关联,以及跨领域(如软件、硬件)的协同。
  5. CL4(定量管理的)
    • 对过程和产品的关键指标进行量化控制(如用统计过程控制 SPC 监控缺陷率),确保过程性能在量化目标范围内波动。
    • 核心:通过数据预测过程趋势,提前预防问题。
  6. CL5(优化的)
    • 利用量化数据和创新方法持续改进过程,主动识别并消除过程瓶颈,同时快速响应内外部变化(如技术革新、市场需求变化)。
    • 关键:建立组织级的改进文化,鼓励通过实验和学习优化过程。

CMM 与 CMMI 的核心区别

维度 CMM CMMI
适用范围 仅针对软件过程 覆盖软件、硬件、系统工程等多领域
评估框架 阶段式(固定级别递进) 支持阶段式和连续式(可按需选择过程域改进)
过程域划分 聚焦软件生命周期的核心过程 更细化,包含工程、管理、支持等多类过程域
灵活性 较固定,需按级别逐步改进 更灵活,允许组织根据优先级选择改进领域

两者的本质目标一致:通过规范化过程提升产品质量、降低成本、提高效率,只是 CMMI 在 CMM 的基础上更具通用性和灵活性,是当前行业更广泛采用的过程改进模型。