吴恩达471机器学习入门课程3第1周——K-means

K-means 聚类

    • 1 - 实现 K-means
      • 1.1 找到最近的质心
      • 练习1
      • 1.2 计算质心均值
      • 练习2
    • 2 - K-means在样本数据集上的应用
    • 3 - 随机初始化
    • 4 - K-means图像压缩
      • 4.1 数据集
        • 可视化
        • 处理数据
      • 4.2图像像素上的 K-mean
      • 4.3 压缩图片

实现 K-means 算法,并将其用于图像压缩。

  • 您将从一个样本数据集开始,帮助您获得 K-means 算法的工作概述
  • 然后,您将使用 K-means 算法进行图像压缩,将出现在图像中的颜色数量减少到仅包括那些在该图像中最常见的颜色。
import numpy as np
import matplotlib.pyplot as plt
from utils import *

%matplotlib inline

1 - 实现 K-means

K-means 算法是一种自动将相似数据点聚合在一起的方法。

  • 具体而言,给定一个训练集 { x ( 1 ) , . . . , x ( m ) } \{x^{(1)}, ..., x^{(m)}\} {x(1),...,x(m)},您想将数据分成几个连贯的“簇”。

  • K-means 是一个迭代过程,它

    • 从猜测初始质心开始,然后
    • 通过
      • 反复将示例分配给其最近的质心,然后
      • 根据分配重新计算质心,来改进这个猜测。
  • 伪代码中,K-means 算法如下:

    # 初始化质心
    # K 是簇的数量
    centroids = kMeans_init_centroids(X, K)
    
    for iter in range(iterations):
        # 聚类分配步骤:
        # 将每个数据点分配到最近的质心
        # idx[i] 对应于分配给第 i 个样本的质心的索引
        idx = find_closest_centroids(X, centroids)
    
        # 移动质心步骤:
        # 根据质心分配计算平均值
        centroids = compute_means(X, idx, K)
    
  • 算法的内循环反复执行两个步骤:

    • (i) 将每个训练样本 x ( i ) x^{(i)} x(i) 分配给其最近的质心,并且
    • (ii) 使用分配给它的点重新计算每个质心的平均值。
  • K K K-means 算法将总是收敛到一些中心点的最终集合。

  • 但是,收敛解决方案可能并不总是理想的,并且取决于质心的初始设置。

    • 因此,在实践中,通常使用不同的随机初始化运行 K-means 算法几次。
    • 选择来自不同随机初始化的这些不同解决方案之间的一种方法是选择具有最低成本函数值(失真)的解决方案。

您将在接下来的部分单独实现 K-means 算法的两个阶段。

  • 您将首先完成 find_closest_centroid,然后继续完成 compute_centroids

1.1 找到最近的质心

在 K-means 算法的“聚类分配”阶段,算法会根据质心的当前位置将每个训练样本 x ( i ) x^{(i)} x(i) 分配给其最近的质心。

练习1

您的任务是完成find_closest_centroids函数中的代码。

  • 此函数接受数据矩阵 X 和所有质心的位置 centroids
  • 它应输出一个一维数组 idx(它具有与 X 相同数量的元素),该数组保存每个训练示例距离最近质心的索引(取值为 { 1 , . . . , K } \{1,...,K\} {1,...,K},其中 K K K 是总质心数)。
  • 具体而言,对于每个示例 x ( i ) x^{(i)} x(i),我们设置
    c ( i ) : = j t h a t    m i n i m i z e s ∣ ∣ x ( i ) − μ j ∣ ∣ 2 , c^{(i)} := j \quad \mathrm{that \; minimizes} \quad ||x^{(i)} - \mu_j||^2, c(i):=jthatminimizes∣∣x(i)μj2,
    其中
    • c ( i ) c^{(i)} c(i) 是与 x ( i ) x^{(i)} x(i) 最接近的质心的索引(对应于起始代码中的 idx [i]),而
    • μ j \mu_j μj 是第 j j j 个质心的位置(值)。(存储在起始代码的 centroids 中)
def find_closest_centroids(x,centroids):
    # 变量idx代表每个样本点所属的最近簇(centroids)的索引值
    idx = np.zeros(x.shape[0],dtype = int)
    # 遍历所有的点
    for i in range(x.shape[0]):
        distance = []
        for j in range(centroids.shape[0]):
            # np.linaly.norm() norm:范数。默认是2,计算欧式距离 平方和开根号
            norm_ij = np.linalg.norm(x[i] - centroids[j])
            distance.append(norm_ij)
        # np.argmin返回的是最小距离那个点所对的索引
        idx[i] = np.argmin(distance)
    return idx
x = load_data()

代码解析

test_x = x[:3]
init = np.array([[3,3], [6,2], [8,5]])
idx = np.zeros(test_x.shape[0],dtype=int)
for i in range(test_x.shape[0]):
    distance = []
    for j in range(init.shape[0]):
        distance.append(np.linalg.norm(x[i]-init[j]))
        print(f"第{i+1}个数据点与第{j+1}个簇点之间的距离:{distance[j]}")
    idx[i] = np.argmin(distance)
    print(f"第{i+1}个数据点属于第{idx[i]+1}个簇点")
第1个数据点与第1个簇点之间的距离:1.981178002041907
第1个数据点与第2个簇点之间的距离:4.907925457663594
第1个数据点与第3个簇点之间的距离:6.170412024053506
第1个数据点属于第1个簇点
第2个数据点与第1个簇点之间的距离:3.2105972663230307
第2个数据点与第2个簇点之间的距离:2.820702783295523
第2个数据点与第3个簇点之间的距离:2.3499462509952416
第2个数据点属于第3个簇点
第3个数据点与第1个簇点之间的距离:3.365171876090534
第3个数据点与第2个簇点之间的距离:1.33813946654494
第3个数据点与第3个簇点之间的距离:2.373852261323399
第3个数据点属于第2个簇点

1.2 计算质心均值

给定每个点与质心的分配,算法的第二阶段重新计算了每个质心所分配到的点的平均值。

练习2

请完成下面的compute_centroids函数以重新计算每个质心的值:

  • 具体而言,对于每个质心 μ k \mu_k μk,我们设置

μ k = 1 ∣ C k ∣ ∑ i ∈ C k x ( i ) \mu_k = \frac{1}{|C_k|} \sum_{i \in C_k} x^{(i)} μk=Ck1iCkx(i)

其中

  • C k C_k Ck 是分配给质心 k k k的示例集合

  • ∣ C k ∣ |C_k| Ck 是集合 C k C_k Ck中示例的数量

  • 具体来说,如果两个示例 x ( 3 ) x^{(3)} x(3) x ( 5 ) x^{(5)} x(5)被分配给质心 k = 2 k=2 k=2,则应更新 μ 2 = 1 2 ( x ( 3 ) + x ( 5 ) ) \mu_2 = \frac{1}{2}(x^{(3)}+x^{(5)}) μ2=21(x(3)+x(5))

def compute_centroids(x,idx,k):
    m,n = x.shape
    centroids = np.zeros((k,n))
    for k in range(k):
        points = x[idx == k]
        # np.mean() 按行计算平均值
        centroids[k] = np.mean(points,axis=0)
    return centroids
m,n = test_x.shape
k_num = 3
test_centroids = np.zeros((k_num,n))
print(idx)
print(f"x:{test_x}")
for k_num in range(k_num):
    points = test_x[idx == k_num]
    print(f"第{k_num}个簇点,points:{points}")
    test_centroids[k_num] = np.mean(points,axis=0)
    print(f"簇点:{test_centroids}")
[0 2 1]
x:[[1.84207953 4.6075716 ]
 [5.65858312 4.79996405]
 [6.35257892 3.2908545 ]]
第0个簇点,points:[[1.84207953 4.6075716 ]]
簇点:[[1.84207953 4.6075716 ]
 [0.         0.        ]
 [0.         0.        ]]
第1个簇点,points:[[6.35257892 3.2908545 ]]
簇点:[[1.84207953 4.6075716 ]
 [6.35257892 3.2908545 ]
 [0.         0.        ]]
第2个簇点,points:[[5.65858312 4.79996405]]
簇点:[[1.84207953 4.6075716 ]
 [6.35257892 3.2908545 ]
 [5.65858312 4.79996405]]

2 - K-means在样本数据集上的应用

当您完成了上面两个函数(find_closest_centroidscompute_centroids)后,下一步是在一个玩具2D数据集上运行K-means算法,以帮助您理解K-means的工作原理。

  • 我们建议您查看下面的函数(run_kMeans)以了解它的工作方式。
  • 注意,代码在循环中调用了您实现的两个函数。

当您运行下面的代码时,它将产生一个可视化图形,展示算法每次迭代的进展情况。

  • 最终,您的图形应该看起来像Figure 1中显示的那样。
def run_kMeans(x,initial_centroids,max_iters =10,plot_progress = False):
    #初始化
    m, n = x.shape
    K = initial_centroids.shape[0]
    centroids = initial_centroids
    previous_centroids = centroids
    idx = np.zeros(m)
    # 运行K-means
    for i in range(max_iters):
        #输出过程
        print("K-Means iteration %d/%d" % (i, max_iters-1))
        # 对于 X 中的每个示例,将其分配给最接近的质心
        idx = find_closest_centroids(x, centroids)
        # 绘制过程
        if plot_progress:
            plot_progress_kMeans(x, centroids, previous_centroids, idx, K, i)
            previous_centroids = centroids
        # 计算新的质点
        centroids = compute_centroids(x, idx, K)
    plt.show()
    return centroids, idx
x = load_data()
initial_centroids = np.array([[3,3],[6,2],[8,5]])
K = 3
max_iters = 10

centroids, idx = run_kMeans(x, initial_centroids, max_iters, plot_progress=True)
K-Means iteration 0/9
K-Means iteration 1/9
K-Means iteration 2/9
K-Means iteration 3/9
K-Means iteration 4/9
K-Means iteration 5/9
K-Means iteration 6/9
K-Means iteration 7/9
K-Means iteration 8/9
K-Means iteration 9/9

png

3 - 随机初始化

为了使您在示例数据集的初始质心分配中看到与“图1”相同的图形,该图形的设计是这样的。在实践中,初始化质心的一个良好策略是从训练集中选择随机样本。

在此练习的这部分中,您应该理解如何实现kMeans_init_centroids函数。

  • 代码首先随机洗牌示例的索引(使用np.random.permutation())。
  • 然后,它基于索引的随机排列选择前 K K K个示例。
    • 这允许随机选择示例,而不会冒选择相同示例的风险。
def kMeans_init_centroids(x,k):
    # 先将数据随机排列
    randidx = np.random.permutation(x.shape[0])
    # 初始簇取随机排列数组前K个
    centroids = x[randidx[:k]]
    return centroids
np.random.permutation(x.shape[0])
array([ 75,  26, 162, 111, 270,  85,   4, 171, 250, 135,  25, 144, 217,
       130, 136, 104, 143, 126,  50, 196, 148,  45, 272,  10, 175,  49,
       125, 179, 221, 169, 296,   1, 282, 204, 197, 241,  78, 290, 205,
        18,  77, 189, 283,  40, 299, 247,   3,  41, 226,  74,  30,  63,
        22, 249, 281,  16, 102,  20, 147, 245, 214, 211, 201, 122,  53,
       220, 252, 218,  73, 255,  83, 229, 219, 159, 206, 181, 156, 109,
       101, 133, 216,  64, 209, 231, 132,  31,  27,  58,  59, 150,  55,
       225, 110, 149, 103,  91, 273, 105, 295,  33, 277, 224, 268, 182,
       200, 235, 262,  15, 127, 119,  86, 285,  57,  35, 165,  80, 167,
        51, 163, 173, 146,  43,   2, 198, 276,  62, 244, 120, 227, 138,
        96,  48, 236, 258, 203, 240, 199,  82, 195,  68, 246,  92, 188,
       164, 155, 153, 187, 183, 280, 141, 113, 284, 174, 260, 215, 267,
       213,  23, 112, 116, 266,  34,  99, 178, 297, 210, 137,  29,  87,
       117, 230,  21, 288, 145,  44, 191, 192, 168, 121,  60, 271,   0,
       237, 291, 251, 157,  89, 264, 242,  32, 142, 177,  39, 294, 234,
        95, 186,  61,  71,  66,  17, 129,  90, 134, 222,   7,  93,  56,
       265, 298,  52, 176, 128,  70, 152,  98, 139, 261, 208,  11, 124,
       212,  76, 228, 151, 238, 207, 278, 123, 158, 115, 223,  14, 274,
       239, 202,  42,  72,  13, 232, 289, 279, 184, 194,  19, 193,  46,
       114, 108,   9, 286, 180, 248, 154,  37, 166, 257, 292, 293, 269,
       107, 259,  79,  12, 106, 256,  97, 287, 170, 185,   5,   8,  84,
        38,  47,  94,  88,  36, 233,  28, 190, 243, 131,  81,   6, 140,
       160, 253, 172, 118,  69, 161, 254, 263,  65,  67, 275, 100,  54,
        24])

4 - K-means图像压缩

在这个练习中,你将使用K-means算法对图像进行压缩。

  • 在直接使用24位颜色表示图像的情况下 2 ^{2} 2,每个像素都表示为三个8位无符号整数(范围从0到255),指定了红色,绿色和蓝色强度值。这种编码通常称为RGB编码。
  • 我们的图片包含成千上万种颜色,在本部分中,您将把颜色数量减少到16种颜色。
  • 通过进行此缩减,可以以高效的方式表示(压缩)照片。
  • 具体而言,您只需要存储选定16种颜色的RGB值,并且对于图像中的每个像素,您现在只需要存储该位置的颜色索引(仅需要4位即可表示16种可能性)。

在本部分中,您将使用K-means算法来选择用于表示压缩图像的16种颜色。

  • 具体而言,您将将原始图像中的每个像素视为数据示例,并使用K-means算法在3维RGB空间中找到最佳聚集(聚类)像素的16种颜色。
  • 一旦您已经在图像上计算出聚类中心,您将使用16种颜色来替换原始图像中的像素。

image-20230618193852767

本练习中提供的照片归Frank Wouters所有,已获得其许可。

4.1 数据集

加载图片

首先,您将使用matplotlib读取原始图像,如下所示。

original_img = plt.imread('bird_small.png')

可视化

plt.imshow(original_img)
<matplotlib.image.AxesImage at 0x25eb49fb640>

png

如您所见,这将创建一个三维矩阵original_img,其中

  • 前两个索引标识像素位置,
  • 第三个索引表示红色、绿色或蓝色。

例如,original_img [50,33,2]给出了行50和列33处像素的蓝色强度。

处理数据

要调用run_kMeans,您需要首先将矩阵original_img转换为二维矩阵。

  • 以下代码重新塑造矩阵original_img以创建像素颜色的 m × 3 m \times 3 m×3矩阵(其中 m = 16384 = 128 × 128 m=16384 = 128\times128 m=16384=128×128
# 将所有值除以255,使所有值都在0-1范围内
original_img = original_img / 255

# 重新构造图像成为 m x 3矩阵,其中 m = 128 x 128 = 16384
# 每一行将包含红色、绿色和蓝色像素值
# 这给我们提供了我们将在K-Means上使用的数据集矩阵X_img。

X_img = np.reshape(original_img, (original_img.shape[0] * original_img.shape[1], 3))

4.2图像像素上的 K-mean

现在,运行下面的单元格以在预处理的图像上运行 K-均值。

K = 16
max_iters = 10
initial_centroids = kMeans_init_centroids(X_img,K)

centroids,idx = run_kMeans(X_img,initial_centroids,max_iters)
K-Means iteration 0/9
K-Means iteration 1/9
K-Means iteration 2/9
K-Means iteration 3/9
K-Means iteration 4/9
K-Means iteration 5/9
K-Means iteration 6/9
K-Means iteration 7/9
K-Means iteration 8/9
K-Means iteration 9/9
print("Shape of idx:", idx.shape)
print("Closest centroid for the first five elements:", idx[:5])
Shape of idx: (16384,)
Closest centroid for the first five elements: [7 6 6 7 7]

4.3 压缩图片

找到用于表示图像的前 K = 16 K=16 K=16种颜色后,现在可以使用find_closest_centroids函数将每个像素位置分配给它最接近的质心。

  • 这使您可以使用每个像素的质心赋值来表示原始图像。
  • 请注意,您已经大大减少了描述图像所需的位数。
    • 原始图像需要每个 128 × 128 128\times128 128×128像素位置的24位,因此总大小为 128 × 128 × 24 = 393 , 216 128 \times 128 \times 24 = 393,216 128×128×24=393,216位。
    • 新的表示形式需要一些开销的存储,以字典的形式存储16种颜色,每种颜色需要24位,但是图像本身只需要每个像素位置4位。
    • 因此最终使用的位数为 16 × 24 + 128 × 128 × 4 = 65 , 920 16 \times 24 + 128 \times 128 \times 4 = 65,920 16×24+128×128×4=65,920位,这相当于将原始图像压缩约6倍。
# 用索引表示图像
X_recovered = centroids[idx, :]
# 将恢复的图像重新调整为正确的维度
X_recovered = np.reshape(X_recovered, original_img.shape)

最后,您可以基于仅质心赋值来重新构建图像,以查看压缩的效果。

  • 具体而言,您可以将每个像素位置替换为分配给它的质心的均值。
  • 图3显示了我们得到的重建图像。即使结果图像保留了大部分原始特征,我们也能看到一些压缩伪影。

image-20230618193952322

fig, ax = plt.subplots(1,2, figsize=(8,8))
plt.axis('off')
# 原始
ax[0].imshow(original_img*255)
ax[0].set_title('Original')
ax[0].set_axis_off()


# 压缩
ax[1].imshow(X_recovered*255)
ax[1].set_title('Compressed with %d colours'%K)
ax[1].set_axis_off()

png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/31087.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

fscan安装配置(windows、linux系统)

fscan安装配置(windows、linux系统) 1、简介 fscan一款内网综合扫描工具&#xff0c;方便一键自动化、全方位漏扫扫描。 它支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写公钥、计划任务反弹shell、读取win网卡信息、web指纹识别、web漏洞扫描、netbios探…

qt 时间编程之时钟

这里写目录标题 开启time格式自动 QTIM打点 qtime qt的时间类 qtimer qt的定时类 头文件包含以及定义 #include<QTime> #include<QTimer>QTime * time; QTimer * timer;开启 右键槽 timer start&#xff08;50&#xff09; 到达50毫米的时候会触发 time out信号…

AcWing801: 二进制中1的个数(两种方法详解)

原题引出 方法一&#xff1a;使用lowbit 算法的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)&#xff0c;使用lowbit操作&#xff0c;每次操作截取一个数字的最后一个1后面的所有位&#xff0c;每次减去lowbit得到的数字&#xff0c;直到数字减到0&#xff0c;就得到了最终…

基于SSM+jsp的电子商城系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Redis原理 - 内存策略

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis 本身是一个典型的 key-value 内存存储数据库&#xff0c;因此所有的 key、value 都保存在之前学习过的 Dict 结构中。不过在其 database 结构体中&#xff0c;有两个 Dict &#xff1a;一个用来记录 key-value&#xf…

day1

在linux内核中&#xff0c;当用户打开设备文件时&#xff0c;内核中的VFS层会调用设备驱动中的sys_open()函数&#xff0c;在sys_open()函数中&#xff0c;内核会根据文件的inode号判断文件是否存在于文件系统中&#xff0c;如果存在&#xff0c;内核会找到这个文件的文件信息结…

翻筋斗觅食策略改进灰狼算法(IGWO)

目录 一、动态扰动因子策略 二、翻筋斗觅食策略 三、改进灰狼算法收敛曲线图 灰狼优化算法存在收敛的不合理性等缺陷&#xff0c;目前对GWO算法的收敛性改进方式较少&#xff0c;除此之外&#xff0c;当GWO迭代至后期&#xff0c;所有灰狼个体都逼近狼、狼、狼&#xff0c;…

A Neural Conversational Model 读后感

目录 摘要 1、介绍 2、相关工作 3、模型 4、数据&#xff08;后面都是具体的东西&#xff0c;不赘述&#xff09; 5、总结 使用微软翻译得到的中文原文&#xff1a; 摘要 会话建模是自然语言理解和机器智能中的一项重要任务。尽管存在以前的方法&#xff0c;但它们通常仅…

React中的HOC高阶组件处理

先了解函数柯里化 柯里化函数&#xff08;Currying Function&#xff09;是指将一个接受多个参数的函数转化成一系列只接受单个参数的函数&#xff0c;并且返回接受单个参数的函数&#xff0c;达到简化函数调用和提高可读性的目的。 简单来说&#xff0c;柯里化即将接收多个参…

Pytorch数据类型Tensor张量操作(操作比较全)

文章目录 Pytorch数据类型Tensor张量操作一.创建张量的方式1.创建无初始化张量2.创建随机张量3.创建初值为指定数值的张量4.从数据创建张量5.生成等差数列张量 二.改变张量形状三.索引四.维度变换1.维度增加unsqueeze2.维度扩展expand3.维度减少squeeze4.维度扩展repeat 五.维度…

Jenkins-pipeline自动化构建Java应用

本实验操作需要&#xff1a;Jenkins&#xff0c;git代码仓库&#xff08;如gitlab&#xff0c;gitee等都可以&#xff09;&#xff0c;maven&#xff0c;docker&#xff0c;docker镜像仓库&#xff08;habor&#xff0c;nexus或者阿里云ACR等&#xff09;以及k8s环境。 前期准…

Python网络爬虫基础进阶到实战教程

文章目录 认识网络爬虫HTML页面组成Requests模块get请求与实战效果图代码解析 Post请求与实战代码解析 发送JSON格式的POST请求使用代理服务器发送POST请求发送带文件的POST请求 Xpath解析XPath语法的规则集&#xff1a;XPath解析的代码案例及其详细讲解&#xff1a;使用XPath解…

k8s使用ceph存储

文章目录 初始化操作k8s使用ceph rbdvolumePV静态pv动态pv k8s使用cephfsvolume静态pv 初始化操作 ceph创建rbd存储池 ceph osd pool create k8s-data 32 32 replicated ceph osd pool application enable k8s-data rbd rbd pool init -p k8s-dataceph添加授权&#xff0c;需…

吴恩达ChatGPT《Building Systems with the ChatGPT API》笔记

1. 课程介绍 使用ChatGPT搭建端到端的LLM系统 本课程将演示使用ChatGPT API搭建一个端到端的客户服务辅助系统&#xff0c;其将多个调用链接到语言模型&#xff0c;根据前一个调用的输出来决定使用不同的指令&#xff0c;有时也可以从外部来源查找信息。 课程链接&#xff1a…

client-go的Indexer三部曲之三:源码阅读

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 《client-go的Indexer三部曲》全部链接 基本功能性能测试源码阅读 本篇概览 本文是《client-go的Indexer三部曲》系列的终篇&#xff0c;主要任务是阅读和…

VR全景智慧园区,沉浸式数字化体验,720度全视角展示

导语&#xff1a; 随着科技的迅猛发展&#xff0c;虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;全景技术已经成为了人们趋之若鹜的新兴领域。 而城市园区作为现代社会的重要组成部分&#xff0c;也正在积极寻求创新的方式来吸引更多的人流和投资。 一&…

C++基础

C基础入门 1 C初识 1.1 第一个C程序 编写一个C程序总共分为4个步骤 创建项目创建文件编写代码运行程序 1.1.1 创建项目 ​ Visual Studio是我们用来编写C程序的主要工具&#xff0c;我们先将它打开 1.1.2 创建文件 右键源文件&#xff0c;选择添加->新建项 1.1.3 编…

SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

SignalR快速入门 ~ 仿QQ即时聊天&#xff0c;消息推送&#xff0c;单聊&#xff0c;群聊&#xff0c;多群公聊&#xff08;基础》提升&#xff0c;5个Demo贯彻全篇&#xff0c;感兴趣的玩才是真的学&#xff09; 官方demo:http://www.asp.net/signalr/overview/getting-started…

【面试】标准库相关题型(二)

文章目录 1. deque底层实现原理1.1 概述1.2 原理图1.3 类结构1.4 操作函数 2. 什么时候使用vector、list、deque2.1 vector2.2 list2.3 deque 3. priority_queue的底层实现原理3.1 一句话概括&#xff1a;用堆来实现优先级队列3.2 堆结构3.3 底层容器3.4 STL对堆结构提供的接口…

Java-API简析_java.lang.SecurityManager类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131346082 出自【进步*于辰的博客】 其实我的【Java-API】专栏内的博文对大家来说意义是不大的。…
最新文章