/*
Name: 稀疏矩阵的三元组顺序表存储表示及基本操作
Copyright: 
Author: 巧若拙 
Date: 27-10-14 21:28
Description: 
------------------------------------------------------------------------------
在实际应用中,我们经常碰到这样一类矩阵,它们的非零元素很少,而且分布没有规律,
我们称之为稀疏矩阵。很显然,若用二维数组存储稀疏矩阵,将浪费大量的时间和空间。因此
我们对稀疏矩阵一般采取压缩存储的方法,即只存储其非零元素。常用的数据结构有三元组顺序表 
和十字链表。
我们先来看三元组顺序表。
//------稀疏矩阵的三元组顺序表存储表示-------------------
*/
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>

#define MAXSIZE 1000 //假设非零元素的个数最多为1000个 
#define N 30 //假设二维数组的列数最多为30

typedef int ElemType;

typedef struct
{
int x, y;  //该非零元素的行下标和列下标 
ElemType e; //该非零元素的值 
} Triple;

typedef struct
{
Triple data[MAXSIZE]; //非零元素三元组顺序表
int mu, nu, tu;   //矩阵的行数,列数和非零元素的个数 
} TSMatrix;
//data域中表示非零元素的三元组是以行序为主序顺序排列的,这为我们的某些计算将带来方便。

TSMatrix CreateTriple(int m, int n); //构造一个三元组顺序表存储矩阵
void CreateArray(int H[][N], int m, int n);  //构造一个二维数组存储矩阵
void PrintArray(int H[][N], int m, int n) ; //输出二维数组存储矩阵
void PrintTriple(TSMatrix M);//输出三元组顺序表存储矩阵
TSMatrix ArrayToTriple(int A[][N], int m, int n);//二维数组转换为三元组顺序表 
void TripleToArray(TSMatrix T, int A[][N], int *m, int *n);//三元组顺序表转换为二维数组
TSMatrix TransposeSMatrix(TSMatrix M);//三元组顺序表 转置矩阵
TSMatrix FastTransposeSMatrix(TSMatrix M); //三元组顺序表 快速转置矩阵
TSMatrix AddSMatrix(TSMatrix A, TSMatrix B); //三元组顺序表 矩阵相加
int Value(TSMatrix M, int i, int j); //计算出C的行号i和列号j处元素的值
TSMatrix MultSMatrix(TSMatrix A, TSMatrix B);//三元组顺序表 矩阵相乘
void RPos(TSMatrix M, int rpos[]);//确定矩阵的每一行的第一个非零元素在三元组顺序表中的位置
TSMatrix FastMultSMatrix_1(TSMatrix A, TSMatrix B);//三元组顺序表 矩阵相乘快速乘法之一
TSMatrix FastMultSMatrix_2(TSMatrix A, TSMatrix B);//三元组顺序表 矩阵相乘快速乘法之二

int main(void)
{
int A[N][N], B[N][N]; //存储矩阵的二维数组 
TSMatrix Triple1, Triple2, Triple3, Triple4, Triple5;   //三元组顺序表
int m, n;

m = 4;
n = 3;
Triple1 = CreateTriple(m, n); //构造一个三元组顺序表存储矩阵
PrintTriple(Triple1);
TripleToArray(Triple1, A, &m, &n);//三元组顺序表转换为二维数组
PrintArray(A, m, n);  //输出矩阵行列式

m = 3;
n = 2;
Triple2 = CreateTriple(m, n); //构造一个三元组顺序表存储矩阵
PrintTriple(Triple2);
TripleToArray(Triple2, B, &m, &n);//三元组顺序表转换为二维数组
PrintArray(B, m, n);  //输出矩阵行列式

Triple3 = MultSMatrix(Triple1, Triple2);//三元组顺序表 矩阵相乘
PrintTriple(Triple3);
TripleToArray(Triple3, B, &m, &n);//三元组顺序表转换为二维数组
PrintArray(B, m, n);  //输出矩阵行列式

printf("\n");
Triple4 = FastMultSMatrix_1(Triple1, Triple2);//三元组顺序表 矩阵相乘
PrintTriple(Triple4);
TripleToArray(Triple4, B, &m, &n);//三元组顺序表转换为二维数组
PrintArray(B, m, n);  //输出矩阵行列式

printf("\n");
Triple5 = FastMultSMatrix_2(Triple1, Triple2);//三元组顺序表 矩阵相乘
PrintTriple(Triple5);
TripleToArray(Triple5, B, &m, &n);//三元组顺序表转换为二维数组
PrintArray(B, m, n);  //输出矩阵行列式

system("pause");
  return 0;
}

void CreateArray(int H[][N], int m, int n) //构造一个二维数组存储矩阵 
{
int i, j;

for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
scanf("%d", &H[i][j]);
fflush(stdin);
}
}

void PrintArray(int H[][N], int m, int n) //输出二维数组存储矩阵 
{
int i, j;

for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
printf("%4d ", H[i][j]);
printf("\n");
}
}

TSMatrix CreateTriple(int m, int n) //构造一个三元组顺序表存储矩阵
{
TSMatrix T;
int i = -1;

puts("请按行序为主序依次输入矩阵的非零元素的行号,列号和元素值,每行输入一个元素的信息:");
printf("注意行号不能超过%d,列号不能超过%d\n", m, n);
do {     
i++;                                          
scanf("%d%d%d", &T.data[i].x, &T.data[i].y, &T.data[i].e);
fflush(stdin);
} while (T.data[i].x > 0 && T.data[i].x <= m && T.data[i].y > 0 && T.data[i].y <= n) ;
T.mu = m;
T.nu = n;
T.tu = i;

return T;
}

void PrintTriple(TSMatrix M)  //输出三元组顺序表存储矩阵
{
int i;

printf("\n");
for (i=0; i<M.tu; i++)//扫描M的所有元素 
printf("M%d(%d,%d,%d)\t", i, M.data[i].x, M.data[i].y, M.data[i].e);
printf("\n");
}

TSMatrix ArrayToTriple(int A[][N], int m, int n)//二维数组转换为三元组顺序表 
{
TSMatrix T;
int i, j, k;

k = 0;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
if (A[i][j] != 0)
{
T.data[k].x = i + 1; 
T.data[k].y = j + 1; 
T.data[k++].e = A[i][j];
}
T.mu = m;
T.nu = n;
T.tu = k;  
 
return T;
}

void TripleToArray(TSMatrix T, int A[][N], int *m, int *n)//三元组顺序表转换为二维数组
{
int i, j, k;

*m = T.mu;
*n = T.nu;
for (i=0; i<*m; i++) //先设所有元素均为0 
for (j=0; j<*n; j++)
A[i][j] = 0;

for (i=0; i<T.tu; i++)//把三元组顺序表中的元素写入二维数组
A[T.data[i].x-1][T.data[i].y-1] = T.data[i].e;
} //注意二维数组的下标从0开始,而三元组顺序表的行,列下标从1开始 
   
//1。转置矩阵
// 显然,一个稀疏矩阵的转置矩阵仍然是稀疏矩阵。假设a和b是TSMatrix型的变量,分别表示矩阵M和T。
//那么,如何由a得到b呢?
// 从分析a和b之间的差异可见只要做到:1。将矩阵的行列值互换;2。将每个三元组中的i和j互换;
//3。重排三元组之间的次序便可以实现矩阵的转置。
// 前两条是容易做到的,关键是如何实现第三条,即如何使b.data中的三元组是以T的行序(M的列序)为主序依次排列的。
// 可以有两种处理方法:
//1,按照b.data中三元组的次序依次在a.data中找到相应的三元组进行转置。即按照M的列序来进行转置。
//其函数如下; 
TSMatrix TransposeSMatrix(TSMatrix M)//三元组顺序表 转置矩阵
{
int k, i, col;
TSMatrix T;

T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;

if (T.tu > 0)
{
k = 0;
for (col=1; col<=M.nu; col++) //按照T的行序(M的列序)为主序依次排列 
for (i=0; i<M.tu; i++)//扫描M的所有元素 
if (M.data[i].y == col) 
{
T.data[k].x = M.data[i].y;
T.data[k].y = M.data[i].x;
T.data[k++].e = M.data[i].e;
}
}

return T;
}

//算法的时间复杂度为O(mu.tu),而使用二维数组存储进行转置矩阵运算时时间复杂度为
//O(mu.nu)。所以此算法仅适用于tu《mu.nu的情况。
//
//2。按照a.data中三元组的次序进行转置,并将转置后的三元组置入b中恰当的位置。
//即预先确定M中每一列(即T中的每一行)的第一个非零元素在b.data中应有的位置。在此,
//需要附设num和cpot两个数组,num[col-1]表示矩阵M中第col列中非零元素的个数,cpot[col-1]
//指示M中第col列中第一个非零元素在b.data中的位置,显然有:
//cpot[0] = 0;
//cpot[col] = cpot[col-1] + num[col-1]  0<col<a.nu
//此算法的时间复杂度为O(mu+tu),在M的非零元素的个数tu和mu*nu等数量级时,其时间复杂度为O(mu.nu),
//和使用二维数组存储进行转置矩阵运算时时间复杂度相同,故称为快速转置。 
//其函数如下; 
TSMatrix FastTransposeSMatrix(TSMatrix M)  //三元组顺序表 快速转置矩阵
{
TSMatrix T;
int k, i, col;
int num[N] = {0};
int cpot[N] = {0};

T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;

if (T.tu > 0)
{
for (i=0; i<M.tu; i++)//扫描M的所有元素 
num[M.data[i].y-1]++; //确定矩阵M每一列中非零元素的个数 
cpot[0] = 0;
for (col=1; col<M.nu; col++)
cpot[col] = cpot[col-1] + num[col-1];// 确定矩阵M第col列中第一个非零元素在b.data中的位置

for (i=0; i<M.tu; i++)//扫描M的所有元素 
{
col = M.data[i].y - 1; //标出该元素所在的列 
k = cpot[col];   //k即矩阵M第col列(即T中的第col行)中第一个非零元素在b.data中的位置 
T.data[k].x = M.data[i].y;
T.data[k].y = M.data[i].x;          
T.data[k].e = M.data[i].e;
cpot[col]++; //矩阵M第col列中第一个非零元素在b.data中的位置向前移动一位 
}
}
return T;
}

//2。矩阵相加
//基本算法,依次扫描A和B的行列值,并且以行序为主序。当行列相同时,将两个元素值相加产生
//的结果放入结果数组中;不相同时,将A或B的元素直接放入结果数组中。
// 这种算法的时间复杂度为O(A.tu+B.tu),速度非常快。其函数如下;
TSMatrix AddSMatrix(TSMatrix A, TSMatrix B) //三元组顺序表 矩阵相加
{
TSMatrix C;
int i=0, j=0, k=0; //i,j,k分别是A,B,C的下标,这些下标都是从0开始的

while (i < A.tu && j < B.tu)//循环直到A,B 中有一个结束 
{
if ((A.data[i].x < B.data[j].x) || ((A.data[i].x == B.data[j].x) && (A.data[i].y < B.data[j].y))) //将A的元素直接放入C中
{   
C.data[k].x = A.data[i].x;
C.data[k].y = A.data[i].y;
C.data[k++].e = A.data[i++].e;  
}
else if ((A.data[i].x > B.data[j].x) || ((A.data[i].x == B.data[j].x) && (A.data[i].y > B.data[j].y))) //将B的元素直接放入C中
{  
C.data[k].x = B.data[j].x;
C.data[k].y = B.data[j].y;
C.data[k++].e = B.data[j++].e;    
}
else //二者相加 

C.data[k].x = A.data[i].x;
C.data[k].y = A.data[i].y;
C.data[k].e = A.data[i++].e + B.data[j++].e;  
if (C.data[k].e != 0) //结果值不为0时放入C中 
k++;
}
}

if (i == A.tu) //A结束,若B还有元素,则将B的元素直接放入C中 
{   
while (j < B.tu)
{
C.data[k].x = B.data[j].x;
C.data[k].y = B.data[j].y;
C.data[k++].e = B.data[j++].e;    
}
}  
else //B结束,若A还有元素,则将A的元素直接放入C中 
{   
while (i < A.tu)
{
C.data[k].x = A.data[i].x;
C.data[k].y = A.data[i].y;
C.data[k++].e = A.data[i++].e;  
}
}

C.mu = A.mu;
C.nu = A.nu;
C.tu = k;

return C;
}

//3。矩阵相乘
// 压缩存储的矩阵与用二维数组存储的矩阵在进行乘法运算时最大的不同是,在经典(二维数组存储)算法中,
//不论M(i,k)和N(k,j)的值是否为零,都要进行一次乘法计算,这样造成很大的浪费。
//而压缩存储则只需在M.data和N.data中找到相应的元素相乘即可。
//这里采用三种算法。
// 第一种,通过给定的行号i和列号j找出原矩阵的对应的元素,设计一个函数Value,当在三元组顺序表中找到该元素时,返回其元素值,
//否则说明该位置元素值为0,返回0。然后利用该函数计算出C的行号i和列号j处元素的值,若该值不为0,则存入C,否则不存入。
//其函数如下;
int Value(TSMatrix M, int i, int j) //计算出矩阵M的i行j列处元素的值
{
int k = 0;
 
while (k < M.tu && M.data[k].x <= i) //因为是按行序排列,故不必扫描行号比i大的元素 
{
if (M.data[k].x == i && M.data[k].y == j)
return M.data[k].e;
k++;
}

return 0;
}

TSMatrix MultSMatrix(TSMatrix A, TSMatrix B)//三元组顺序表低效矩阵乘法
{
TSMatrix C;
int i, j, k, l, p, s;

C.mu = A.mu;
C.nu = B.nu;
C.tu = 0;

if (A.tu * B.tu != 0)
{
p = 0;
for (i=1; i<=A.mu; i++)
{
for (j=1; j<=B.nu; j++)
{
s = 0;
for (k=1; k<=A.nu; k++)
s += Value(A, i, k) * Value(B, k, j);

if (s != 0)
{
C.data[p].x = i;
  C.data[p].y = j;
C.data[p++].e = s;
}

}

C.tu = p;
}

return C;
}

//这种算法的存储空间虽然很少,但时间复杂度为O(A.mu*A.nu*B.nu*(A.tu+B.tu)),比经典的算法时间复杂度还高,
//因此是一种用时间换空间的方法。 
// 如果我们预先确定矩阵的每一行的第一个非零元素在三元组顺序表中的位置,则可以得到改进的算法。
//基本操作是对于A中每个元素A.data[p],找到N中所有满足条件A.data[p].y==B.data[q].x的元素B.data[q],
//求得A.data[p].e和B.data[q].e的乘积,当然这个乘积的值只是乘积矩阵C[i][j]中的一部分。
//为了便于操作,我们可以对每个元素设置一个累计乘积值的变量,使其初值为0,然后扫描A,求得相应元素的乘积值并累积到相应的累计乘积值的变量中。
// 由于C中元素的行号和A中元素的行号一致,又都是以行序为主序排列的,因此可以对C进行逐行处理。
// 其函数如下;
void RPos(TSMatrix M, int rpos[])//确定矩阵的每一行的第一个非零元素在三元组顺序表中的位置
{
int num[N] = {0};
int i, row;

for (i=0; i<M.tu; i++)//扫描M的所有元素 
num[M.data[i].x-1]++; //确定矩阵M每一行中非零元素的个数

rpos[0] = 0;
for (row=1; row<M.mu; row++)
rpos[row] = rpos[row-1] + num[row-1];// 确定矩阵M第row行中第一个非零元素在M.data中的位置
}

TSMatrix FastMultSMatrix_1(TSMatrix A, TSMatrix B)//三元组顺序表快速矩阵乘法之一 
{   
TSMatrix C;
int Arpos[N] = {0}, Brpos[N] = {0};//分别存储矩阵A,B的每一行的第一个非零元素在三元组中的位置 
int ctemp[N] = {0};//存储正在处理的该行中每一列的乘积值,是一个累积的和值,作为矩阵C在该位置处元素的值 
int arow, brow, ccol;
int i, p, q;
int ta, tb;

C.mu = A.mu;
C.nu = B.nu;
C.tu = 0;

if (A.tu * B.tu != 0)//若C是非零矩阵 
{
RPos(A, Arpos); //确定矩阵A的每一行的第一个非零元素在三元组顺序表中的位置
RPos(B, Brpos); //确定矩阵B的每一行的第一个非零元素在三元组顺序表中的位置

for (arow=1; arow<=A.mu; arow++)//对A进行逐行处理 ,即对C进行逐行处理 
{
for (i=0; i<B.nu; i++)//当前各元素累加器清零 
ctemp[i] = 0;

if (arow < A.mu) //处理A中第arow行的每一个非零元素,ta指示下一行第一个非零元素的位置 
ta = Arpos[arow];
else   //最后一行的 下一行第一个非零元素的位置 当然是  A.tu
ta = A.tu;

for (p=Arpos[arow-1]; p<ta; p++) //处理第arow的每一个非零元素,由p指示其位置 
{
brow = A.data[p].y; //标出该元素的列号,在B中找到与它对应的行号 
if (brow < B.mu)//处理B中第brow行的每一个非零元素,tb指示下一行第一个非零元素的位置
tb = Brpos[brow];
else
tb = B.tu;

for (q=Brpos[brow-1]; q<tb; q++)//处理A中第arow行时,该行的每一个元素与B中对应元素
{                           //(A的列数对应B的行数)均乘一次,乘积值累积在ctemp[ccol]中, 
ccol = B.data[q].y - 1;       //直到该行所有的元素都处理完毕,再把ctemp[ccol]的值放入C中 
ctemp[ccol] += A.data[p].e * B.data[q].e;

}
 
for (ccol=0; ccol<C.nu; ccol++)//得到C的第arow中每一列(个)元素的值 
{
if (ctemp[ccol] != 0)//压缩存储该行非零元
{
if (C.tu == MAXSIZE)
{
printf("三元组溢出!\n" );
exit(1);
}
C.data[C.tu].x = arow; //C的行数等于A的行数 
C.data[C.tu].y =ccol + 1; //C的列数等于B的列数 
C.data[C.tu++].e = ctemp[ccol]; //C的元素值等于A的行数ctemp[ccol]的累积值 

}

}

return C;
}

// 分析上述算法的时间复杂度有如下结果:确定矩阵的每一行的第一个非零元素在三元组顺序表中的位置的时间复杂度为O(A.tu+A.mu+B.tu+B.mu+),
//累加器ctemp初始化的时间复杂度为O(A.mu*B.nu),C的所有非零元素的时间复杂度为O(A.tu*B.tu/B.mu),进行压缩存储的时间复杂度为O(A.mu*B.tu),
//因此总的时间复杂度为O(A.mu*B.nu + A.tu*B.tu/B.mu)。当矩阵为稀疏矩阵时,这种算法的时间复杂度接近O(A.mu*B.nu)比经典算法要快。

//还有一种快速矩阵乘法,它是先将矩阵B转置,则矩阵A与B的列数就相同了,这样不需要设置数组ctemp[N],只需直接计算该行对应列的元素乘积的总和即可得到矩阵C的值。 
TSMatrix FastMultSMatrix_2(TSMatrix A, TSMatrix B)//三元组顺序表快速矩阵乘法之二 
{   
TSMatrix C;
int Arpos[N] = {0}, Brpos[N] = {0};//分别存储矩阵A,B的每一行的第一个非零元素在三元组中的位置 
int arow, brow, ccol;
int i, p, q;
int ta, tb;

C.mu = A.mu;
C.nu = B.nu;
C.tu = 0;

if (A.tu * B.tu != 0)//若C是非零矩阵 
{
B = FastTransposeSMatrix(B); //求矩阵B的转置矩阵 
RPos(A, Arpos); //确定矩阵A的每一行的第一个非零元素在三元组顺序表中的位置
RPos(B, Brpos); //确定矩阵B的每一行的第一个非零元素在三元组顺序表中的位置

for (arow=1; arow<=A.mu; arow++)//对A进行逐行处理 ,即对C进行逐行处理 
{
ta = (arow < A.mu) ? Arpos[arow] : A.tu;

for (brow=1; brow<=B.mu; brow++)
{
C.data[C.tu].e = 0;
p = Arpos[arow-1];
tb = (brow < B.mu) ? Brpos[brow] : B.tu;
q = Brpos[brow-1];

while (p < ta && q < tb)
{
if (A.data[p].y < B.data[q].y)
p++;
else if (A.data[p].y > B.data[q].y)
q++;
else
C.data[C.tu].e += A.data[p++].e * B.data[q++].e; //C的元素值等于该行对应列的元素乘积的总和
}

if (C.data[C.tu].e != 0)
{
C.data[C.tu].x = arow;
C.data[C.tu++].y = brow;

}

}

return C;
}

稀疏矩阵的三元组顺序表存储表示及基本操作相关推荐

  1. 稀疏矩阵的三元组存储方法c语言,数据结构C语言版 稀疏矩阵的三元组顺序表存储表示和实现...

    陈独秀的秘密 数据结构C语言版 稀疏矩阵的三元组顺序表存储表示和实现 P98 编译环境:Dev-C++ 4.9.9.2 日期:2011年2月8日 */ typedef int ElemType; // ...

  2. 稀疏矩阵(三元组顺序表存储)6种操作的实现

    /* *任务描述:针对稀疏矩阵,实现10个基本操作 * 1:建立稀疏矩阵 : * 2:输出稀疏矩阵 : * 3:转置稀疏矩阵 : * 4:稀疏矩阵相加 : * 5:稀疏矩阵相减: * 6:稀疏矩阵相乘 ...

  3. 数据结构 稀疏矩阵三元组顺序表 基本操作

    [数据结构]稀疏矩阵 三元组顺序表存储 基本操作 1.稀疏矩阵定义: 假设在 mn 的矩阵中,又t个元素不为零.δ = t/mn ,称δ为矩阵的稀疏因子,通常定义δ小于等于0.05时称为稀疏矩阵. 2 ...

  4. c语言三元组作用,三元组顺序表,稀疏矩阵的三元组表示及(C语言)实现

    本节介绍稀疏矩阵的三元组顺序表压缩存储方式. 通过<矩阵的压缩存储>一节我们知道,稀疏矩阵的压缩存储,至少需要存储以下信息: 矩阵中各非 0 元素的值,以及所在矩阵中的行标和列标: 矩阵的 ...

  5. 数组:矩阵快速转置 矩阵相加 三元组顺序表/三元矩阵 随机生成稀疏矩阵 压缩矩阵【C语言,数据结构】(内含源代码)

    目录 题目: 题目分析: 概要设计: 二维矩阵数据结构: 三元数组\三元顺序表顺序表结构: 详细设计: 三元矩阵相加: 三元矩阵快速转置: 调试分析: 用户手册: 测试结果: 源代码: 主程序: 头文 ...

  6. 三元组顺序表表示的稀疏矩阵转置(10分)

    三元组顺序表表示的稀疏矩阵转置(10分) 本题要求实现一个函数,实现三元组顺序表表示的稀疏矩阵转置. 函数接口定义: struct tripletable * trans(struct triplet ...

  7. 2021-10-28 三元组顺序表表示的稀疏矩阵加法

    PTA练习题--稀疏矩阵的加法. 题目分析:此题的核心在于找到行数和列数相等的元素进行求和,若和为零时则舍去,当行数/列数不等时分类进行讨论. 此题共分为七种情况进行讨论,分别为: 1 ai=bi:a ...

  8. 三元组顺序表表示的稀疏矩阵加法

    三元组顺序表表示的稀疏矩阵加法. 输入格式: 输入第1行为两个同型矩阵的行数m.列数n,矩阵A的非零元素个数t1,矩阵B的非零元素个数t2. 按行优先顺序依次输入矩阵A三元组数据,共t1行,每行3个数 ...

  9. 《数据结构》实验报告(一)——顺序表存储结构及实现

    顺序表存储结构及实现--学生信息管理 一.实验目的 (1) 掌握顺序表的概念及实现方式. (2) 掌握顺序表的存储结构及主要运算:建立.查找.插入.删除等. 二.实验环境 Windows 10,Mic ...

最新文章

  1. [原创]一种自动地将继承自NSObject的自定义类序列化成JSON的方法
  2. Hive和HBase
  3. python简单体育竞技模拟_Python程序设计思维练习---体育竞技分析-阿里云开发者社区...
  4. 快速开发后台不用太多代码的 tp5_小程序·云开发优劣简述
  5. vue 新窗口打开外链接
  6. git 上传项目到linux仓库_总结:上传python项目至git上前的一些准备工作
  7. Scality试图将对象存储转移到磁带和云中
  8. SQL Server 数据库调整表中列的顺序操作
  9. 五子棋人机对战_10.带人机对战的五子棋程序
  10. 苹果mac轻量级思维导图软件:Xmind
  11. jquery $(document).ready() 与window.onload的区别(转)
  12. 2021-05-01微信小程序存储数据的几种方式
  13. LaTeX中CTeX版本日期格式设置英文
  14. python爬虫实现豆瓣模拟登录
  15. 大型在线实时应用解决方案
  16. pcntl_alarm()的示例
  17. 网络工程师----成长之路
  18. 使用python批量下载需要的分子的SDF文件
  19. 【Qt OpenGL教程】14:轮廓字体
  20. 为更美好的商业生态,全力以赴

热门文章

  1. homeassistant几种安装方式对比,树莓派4docker安装记录
  2. 多么痛的领悟:13 起惨痛的宕机案例
  3. sklearn分层抽样
  4. 机器学习应该了解的十大算法
  5. 哈工大计算机考研英语,一站上岸哈工大学长的肺腑之言,考研全历程真心分享!...
  6. Linux安装库时安装源错误,linux环境下golang安装第三方库的时候出错的决办法
  7. python蓝桥杯从入门到~
  8. KingbaseES V8R6集群运维案例---数据块故障自动修复(auto_bmr)
  9. [小游戏资源] 微信小游戏开发资源目录
  10. html鼠标移动距离,简单的鼠标移动元素近大远小效果