前言
坐标南山,通信工程,对自己所学内容进行记录和分享,希望可以帮助到有需要的的同学。
一、移动通信中的算法问题
1.算法背景
信号强度核心算法:
相关检测技术:
相关检测技术是信号检测领域里一种重要工具,常用于从噪声背景中检测出有用的确定性信号。它利用确定性信号在不同时刻的取值一般都具有较强相关性,而干扰噪声因为随机性较强,不同时刻取值相关性较差的特性,把确定性信号和干扰噪声区分开来。
假设确定信号序列为x[m],具有噪声背景的实际信号序列为y[n],m<n,通过滑动相关计算,找出滑动相关计算序列z[k]的最大的值,则可以求出具有噪声背景的实际信号序列y中所包含的确定信号序列x的位置。
滑动相关核心算法:
2.核心代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define datafile_N 48
#define pssfile_N 3
#define data_N 30000
#define pss_N 4096
double sum_power(double *arr);
double bubble_sort(double *a, int n);
double slide_re(double *a, double *b);
main()
{
int i=0, j=0, k=0, x, y;
double max;
char order[3]="",path1[50]="C:\\Users\\17513\\Desktop\\data\\data";
char path2[50]="C:\\Users\\17513\\Desktop\\data\\PSS";
char datar[data_N][50];
double datat[data_N];
double power[datafile_N];
double power_sort[datafile_N];
double re_all[3][48];
double re_max[pssfile_N][1];
char pssr[pssfile_N][50];
double psst[pssfile_N][pss_N];
//char pssi[pssfile_N][pss_N/2];
FILE *fp[48];
for(i=0;i<pssfile_N;i++)
{
order[0]=i+'0';
strcat(strcat(path2, order), ".txt");
if((fp[i]= fopen(path2, "r"))==NULL)
printf("\nCannot open the file!");
else
//printf("\nfile %s open successfully!\n",path2);
for(j=0;j<pss_N;j++)
{
fscanf(fp[i],"%lf",&psst[i][j]);
//printf("%lf", psst[i][j]);
}
//for(j=0;j<pss_N;j++)
// printf("\n%lf", psst[i][j]);
strcpy(order,"");
strcpy(path2,"C:\\Users\\17513\\Desktop\\data\\PSS");
}
order[1]=NULL;
for(i=0; i<48; i++)
{
if(i>9)
{
order[1]=i%10 + '0';
order[0]=i/10 + '0';
}
else
order[0]=i+'0';
strcat(strcat(path1, order), ".txt");
if((fp[i]= fopen(path1, "r"))==NULL)
printf("\nCannot open the file!");
else
//printf("file %s open successfully!\n",path1);
for(j=0;j<data_N;j++)
{
fgets(datar[j],50,fp[i]);
datat[j]=atof(datar[j]);
}
power[i]=sum_power(datat);
power_sort[i]=sum_power(datat);
for(j=0;j<3;j++)
{
re_all[j][i]=slide_re(datat, psst[j]);
//bubble_sort(re_all, 12952);
}
/*if(i==47)
for(j=0;j<3;j++)
{ for(k=0;k<48;k++)
printf("%lf ", re_all[j][k]);
printf("\n");
}*/
strcpy(order,"");
strcpy(path1,"C:\\Users\\17513\\Desktop\\data\\data");
}
bubble_sort(power_sort,48);
for(i=0;i<3;i++)
{
max=re_all[i][0];
x = i;
y = 0;
for(j=0;j<48;j++)
{
if(re_all[i][j]>max)
{
max=re_all[i][j];
y=j;
}
}
printf("PSS%d and data%d is the most relevant!\n", x, y);
}
/*for(int l =0;l<48;l++)
{
printf("%d %lf\n", l, power_sort[l]);// 打印排列后的数据
}*/
for(k=0;k<48;k++)
{
if(power[k]==power_sort[47])
printf("\nMAX POWER IS data%d.txt", k);
}
}
double sum_power(double *arr)//计算能量
{
int i=0;
double a=0.0;
for(i=0;i<data_N;i=i+2)
{
a += sqrt(arr[i]*arr[i] + arr[i+1]*arr[i+1]);
}
//printf("\n%lf", a);
return a;
}
double bubble_sort(double *a, int n) //冒泡排序
{
int i,j;
double temp;
//定义三个整型变量
for (j=0;j<n-1;j++) //用一个嵌套循环来遍历一遍每一对相邻元素
{
for (i=0;i<n-1-j;i++)
{
if(a[i]>a[i+1]) //从大到小排就把左边的">"改为"<"
{
temp=a[i]; //a[i]与a[i+1](即a[i]后面那个) 交换
a[i]=a[i+1]; //基本的交换原理"c=a;a=b;b=c"
a[i+1]=temp;
}
}
}
return 0;
}
double slide_re(double *a, double *b)
{
int i, j ,k, location;
double c[(data_N-pss_N)/2+1];
double s, r, v, max;
for(i=0;i<(data_N-pss_N);i+=2)
{
s = 0;
r = 0;
v = 0;
for(j=0;j<pss_N;j=j+2)
{
r += a[j+i]*b[j]+a[j+i+1]*b[j+1];
v += a[j+i]*b[j]-a[j+i]*b[j+1];
}
//s = r + v;
s = pow(r, 2) + pow(v,2);
s = sqrt(s);
c[i/2] = s;
}
max=c[0];
for(i=0;i<12953;i++)
{
if(c[i]>max)
{
max=c[i];
location=i;
}
}
//printf("%d\n",location);
return max;
}
二、通信网中的算法问题
1.算法背景
由于实验要求使用Dijkstra算法计算图的最短路径问题,所以简单介绍一下相关内容
求解问题:
算出此拓扑图中的各个点到其它点的最短路径
**
2.核心思路
**
由于lz没想到什么更好的办法,所以将此拓扑图手动变成矩阵写在一个txt文件中,再通过文件操作读入程序中,然后再进行其他操作。
代码:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
#define INF 10000
int dist[MAX], prev[MAX];
// 邻接矩阵
typedef struct _graph
{
int vexs[MAX]; // 顶点集合
int vexnum; // 顶点数
int edgnum; // 边数
int *matrix; // 一维数组指针偏移表示邻接矩阵
}Graph, *PGraph;
void printf_path(int u,int x);
void dijkstra(Graph G, int vs, int prev[], int dist[], int n);
int *read_Matrix(int *a, int n);
int read_Vex(int i, int n);
main()
{
int i, j, n, vs;
int *a;
int *b;
Graph G;
printf("Please Input The Matrix's Scale:\n");
scanf("%d", &n);
for(i=0;i<n;i++)
{
G.vexs[i]= read_Vex(i, n);
}
G.vexnum = n;
G.edgnum = 0; //顶点数
G.matrix = read_Matrix(a, n); //将文件中的数据读入图的邻接矩阵中
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(G.matrix[i*n+j]>0 && G.matrix[i*n+j]<10000) //读取边数
G.edgnum++;
printf("%-5d ", G.matrix[i*n+j]);
}
printf("\n");
}
printf("\n\n");
do
{
system("pause");
system("cls");
printf("Please Input The Source Code:\n");
scanf("%d", &vs);
if(vs<=0 || vs>n)
break;
dijkstra(G, vs-1, prev, dist, n);
}while(1);
/*for(i=0;i<n;i++)
{
printf("%d ", G.vexs[i]);
}
printf("%d\n", G.edgnum);
*/
}
int read_Vex(int i, int n) //输入顶点编号
{
if(i<n)
return i+1;
else
return -1;
}
int *read_Matrix(int *a, int n)//读取文件中的邻接矩阵
{
int i, j;
char str[10];
FILE *fp;
if((fp = fopen("D:\\Work\\通信软件\\实验二\\MGraph.txt", "r+"))==NULL)
printf("Cannot Open The File!\n");
else
a = (int*)calloc(n*n, sizeof(int)); //分配动态内存
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
fscanf(fp,"%d ", &a[i*n+j]);//指针偏移
}
/*for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%-5d ", a[i*n+j]);
printf("\n");
}*/
fclose(fp);
return a;
}
/*
* Dijkstra最短路径。
* 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
*
* 参数说明:
* G -- 图
* vs -- 起始顶点(start vertex)。即计算"顶点vs对应的数组编号"到其它顶点的最短路径。
* prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
* dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
* n -- 顶点数
*/
void dijkstra(Graph G, int vs, int prev[], int dist[], int n)
{
int i,j,k, m=0;
int min;
int tmp;
int flag[MAX];// flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。
int path[MAX][MAX];
// 初始化
for (i = 0; i < G.vexnum; i++)
{
flag[i] = 0; // 顶点i的最短路径还没获取到。
prev[i] = -1; // 顶点i的前驱顶点为0。
dist[i] = G.matrix[vs*n+i];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。
}
for (i = 0; i < G.vexnum; i++)
{
if(G.matrix[vs*n+i]<INF)
prev[i]=vs;
}
// 对"顶点vs"自身进行初始化
flag[vs] = 1;
dist[vs] = 0;
for (i = 1; i < G.vexnum; i++) // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。
{
min = INF;
for (j = 0; j < G.vexnum; j++)// 寻找当前最小的路径,即在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
{
if (flag[j]==0 && dist[j]<min)
{
min = dist[j];
k = j;
}
}
// 标记"顶点k"为已经获取到最短路径
flag[k] = 1;
// 修正当前最短路径和前驱顶点
// 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
for (j = 0; j < G.vexnum; j++)
{
tmp = (G.matrix[k*n+j]==INF ? INF : (min + G.matrix[k*n+j])); // 防止溢出
if (flag[j] == 0 && (tmp < dist[j]) )
{
dist[j] = tmp;
prev[j] = k;
}
}
}
// 打印dijkstra最短路径的结果
printf("\nThe Vex(%d)'s and others' shortest path: \n", G.vexs[vs]);
for (i = 0; i < G.vexnum; i++)
{
printf("Vex(%d) and Vex(%d)'s shortest path and consume:%d\n", G.vexs[vs], G.vexs[i], dist[i]);
printf_path(vs,i);
}
}
void printf_path(int u,int x) //打印路径和消耗
{
int a[MAX],cou=0,ex=x;
if(u==x)
printf("%d-%d",u+1,x+1);
else if(prev[x]==-1)
printf("%d-%d=∞",u+1,x+1);//没有路径
else
{
while(x!=u)
{
a[cou++]=x;
x=prev[x];
}
a[cou]=x;
for(int i=cou; i>0; i--)
printf("%d-",a[i]+1);
printf("%d",a[0]+1);
}
printf("\n");
}
运行结果:
保证程序的可移植性,手动输入邻接矩阵的大小。
读入数据。
输入源点后得到相应的最短路径。
3.python版本
利用python方便许多,可直接将数据写入excel中,再进行读入,代码也很短
代码:
from pandas import read_excel
import os
path_metrix=read_excel(os.getcwd()+"\\metrix.xlsx")##读取文件用
tu_dict={}##邻接矩阵表示的图
rt_dict={}##一个节点的路由字典
point_queue=[]
#导入邻接矩阵
for i in range(0,len(path_metrix)):
tu_dict["v"+str(i+1)]={}
for j in range(0,len(path_metrix)):
tu_dict["v"+str(i+1)]["v"+str(j+1)]=path_metrix[i][j]
result_file=open("结果.txt","w+")
for h in range(0,len(path_metrix)):
#建立路由字典(v1,v2,v3...vh)
for i in range(0,len(path_metrix)):
rt_dict["v"+str(i+1)]={}
if i==h:
rt_dict["v"+str(i+1)]["dis"]=0
rt_dict["v"+str(i+1)]["n_point"]="v"+str(h+1)
else:
rt_dict["v"+str(i+1)]["dis"]=1000
rt_dict["v"+str(i+1)]["n_point"]="none"
point_queue.append("v"+str(h+1))
##迪杰斯特拉算法开始
while point_queue!=[]:
for v in tu_dict[point_queue[0]]:
if rt_dict[point_queue[0]]["dis"]+tu_dict[point_queue[0]][v]<rt_dict[v]["dis"]:
rt_dict[v]["dis"]=rt_dict[point_queue[0]]["dis"]+tu_dict[point_queue[0]][v]
if str(v) not in point_queue:
point_queue.append(str(v))
rt_dict[v]["n_point"]=str(point_queue[0])
del point_queue[0]
##输出结果
for i in range(1,len(path_metrix)+1):
if i==h+1:
continue
else:
path="v"+str(i)
v=rt_dict["v"+str(i)]["n_point"]
while v!="v"+str(h+1):
path=v+"-"+path
v=rt_dict[v]["n_point"]
path="v"+str(h+1)+"-"+path
result="v"+str(h+1)+"到"+"v"+str(i)+"最短距离:"+str(rt_dict["v"+str(i)]["dis"])+"\t路径:"+path
result_file.write(result+"\n")
print(result)
result_file.write("\n")
print("")
result_file.close()
结果:
三.k-means算法实验
1.算法背景
聚类算法简单介绍:
k-means算法
k-means算法,也被称为k-均值或k-平均。
该算法首先随机地选择k个对象作为初始的k个簇的质心;然后对剩余的每个对象,根据其与各个质心的距离,将它赋给最近的簇,然后重新计算每个簇的质心;这个过程不断重复,直到准则函数收敛。
通常采用的准则函数为平方误差和准则函数,即 SSE(sum of the squared error),其定义如下:
SSE是数据库中所有对象的平方误差总和,p为数据对象,mi是簇Ci的平均值。这个准则函数使生成的结果尽可能的紧凑和独立。
实验所求问题:
通过这三年的数据,将这几只球队分成三类
2.代码实现
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include<iostream>
#include<algorithm>
#define N 15 //数据个数
#define K 3 //聚类个数
#define delta 0.01 //迭代终止的判断条件
using namespace std;
typedef struct
{
double x;
double y;
double z;
int Group;
char name[15];
}Data ;
Data D[N];
Data Dpre[N];
void read_data(Data D[N],int n); //文件读数据
void data_pre_manage(Data D[N], int n); //数据预处理
void K_means(Data D[N], int n, int k);//核心算法
void Code_iteration(double x[], double y[], double z[], int k);//中心点迭代
double dist_cal(double x1, double y1, double z1, double x2, double y2, double z2);//点距离计算
main()
{
int i;
read_data(D, N);
read_data(Dpre,N);
data_pre_manage(Dpre, N);
for(i=0;i<N;i++)
{
printf("%.2lf %.2lf %.2lf %s\n", Dpre[i].x, Dpre[i].y, Dpre[i].z, Dpre[i].name);
}
K_means(Dpre, N, K);
}
void read_data(Data D[N], int n)
{
int i;
FILE *fp;
if((fp = fopen("D:\\Work\\通信软件\\实验三\\World Cup_data.txt", "r+"))==NULL)
printf("Cannot Open The File!\n");
else
for(i=0;i<n;i++)
{
fscanf(fp,"%lf %lf %lf %s", &D[i].x, &D[i].y, &D[i].z, D[i].name);
}
fclose(fp);
}
void data_pre_manage(Data D[N], int n)
{
int i;
double Dx_min=D[0].x, Dx_max=D[0].x;
double Dy_min=D[0].y, Dy_max=D[0].y;
double Dz_min=D[0].z, Dz_max=D[0].z;
for(i=0;i<n;i++)
{
if(Dx_min>D[i].x)
Dx_min=D[i].x;
if(Dx_max<D[i].x)
Dx_max=D[i].x;
if(Dy_min>D[i].y)
Dy_min=D[i].y;
if(Dy_max<D[i].y)
Dy_max=D[i].y;
if(Dz_min>D[i].z)
Dz_min=D[i].z;
if(Dz_max<D[i].z)
Dz_max=D[i].z;
}
for(i=0;i<n;i++)
{
D[i].x = (D[i].x-Dx_min)/(Dx_max-Dx_min);
D[i].y = (D[i].y-Dy_min)/(Dy_max-Dy_min);
D[i].z = (D[i].z-Dz_min)/(Dz_max-Dz_min);
}
//printf("%lf %lf\n",Dx_min, Dx_max );
}
void K_means(Data D[N], int n, int k)
{
int i, j;
int a[K][n], temp;
int num[K]={0,0,0};
double sum_co[K];
double x[K], y[K], z[K];
double dist[n][K];
double code[K][K];
double dist1, dist2, dist3;
srand((unsigned int)time(0));
for(i=0; i<k; i++) //生成随机K个点作为初始中心
{
a[i][0] = rand()%N;
temp=a[i][0];
for(j=0;j<k;j++)//避免产生的随机数重复md
{
if(temp==a[j][0])
temp=rand()%N;
else
break;
}
a[i][0]=temp;
}
printf("The Initial Center point is:\n");
for(j=0;j<k;j++)
{
printf("%d ", a[j][0]);
}
printf("\n");
for(i=0;i<n;i++)
{
for(j=0;j<k;j++)
{
dist[i][j]=dist_cal(Dpre[i].x,Dpre[i].y,Dpre[i].z,Dpre[a[j][0]].x,Dpre[a[j][0]].y,Dpre[a[j][0]].z);//计算距离
}
//cout<<*min_element(dist[i],dist[i]+3)<<' ';
for(j=0;j<k;j++)
{
if(dist[i][j]==*min_element(dist[i],dist[i]+3)) //分组
Dpre[i].Group=j;
}
}
/*for(i=0;i<n;i++)
{
for(j=0;j<k;j++)
{
printf("%lf ", dist[i][j]);
}
cout<<*min_element(dist[i],dist[i]+3)<<' ';
printf("\n");
}*/
for(i=0;i<n;i++)//第一次分组后计算中心点
{
if(Dpre[i].Group==0)
{
num[0]++;
x[0] += Dpre[i].x;
y[0] += Dpre[i].y;
z[0] += Dpre[i].z;
}
else if(Dpre[i].Group==1)
{
num[1]++;
x[1] += Dpre[i].x;
y[1] += Dpre[i].y;
z[1] += Dpre[i].z;
}
else
{
x[2] += Dpre[i].x;
y[2] += Dpre[i].y;
z[2] += Dpre[i].z;
}
//sum_co[i]=x[i]+y[i]+z[i];
}
num[2]=n-num[0]-num[1];
for(i=0;i<k;i++)
{
x[i] /= num[i];
y[i] /= num[i];
z[i] /= num[i];
sum_co[i]=x[i]+y[i]+z[i];
}
//printf("test\n");
dist1=dist_cal(x[0],y[0],z[0],Dpre[a[0][0]].x,Dpre[a[0][0]].y,Dpre[a[0][0]].z);
dist2=dist_cal(x[1],y[1],z[1],Dpre[a[1][0]].x,Dpre[a[1][0]].y,Dpre[a[1][0]].z);
dist3=dist_cal(x[2],y[2],z[2],Dpre[a[2][0]].x,Dpre[a[2][0]].y,Dpre[a[2][0]].z);
if(dist1<delta && dist2<delta && dist3<delta)
{
for(i=0;i<K;i++)
{
if(sum_co[i]==*min_element(sum_co,sum_co+3))
{
printf("The Asia First Class Are:\n");
for(j=0;j<n;j++)
{
if(Dpre[j].Group==i)
printf("%s ", Dpre[j].name);
}
printf("\n");
}
else if(sum_co[i]==*max_element(sum_co,sum_co+3))
{
printf("The Asia Third Class Are:\n");
for(j=0;j<n;j++)
{
if(Dpre[j].Group==i)
printf("%s ", Dpre[j].name);
}
printf("\n");
}
else
{
printf("The Asia Second Classs Are:\n");
for(j=0;j<k;j++)
{
if(Dpre[j].Group==i)
printf("%s ", Dpre[j].name);
}
printf("\n");
}
}
}
else
{
Code_iteration(x, y, z, k);
}
}
void Code_iteration(double x[], double y[], double z[], int k)
{
int i, j, num[k]={0,0,0};
double x_NEW[k], y_NEW[k], z_NEW[k], sum_co[k];
double dist[N][k];
//printf("test\n");
for(i=0;i<N;i++)
{
for(j=0;j<k;j++)
{
dist[i][j]=dist_cal(Dpre[i].x,Dpre[i].y,Dpre[i].z,x[j],y[j],z[j]);//计算距离
}
for(j=0;j<k;j++)
{
if(dist[i][j]==*min_element(dist[i],dist[i]+3)) //分组
Dpre[i].Group=j;
}
}
for(i=0;i<N;i++)//分组后计算中心点
{
if(Dpre[i].Group==0)
{
num[0]++;
x_NEW[0] += Dpre[i].x;
y_NEW[0] += Dpre[i].y;
z_NEW[0] += Dpre[i].z;
}
else if(Dpre[i].Group==1)
{
num[1]++;
x_NEW[1] += Dpre[i].x;
y_NEW[1] += Dpre[i].y;
z_NEW[1] += Dpre[i].z;
}
else
{
x_NEW[2] += Dpre[i].x;
y_NEW[2] += Dpre[i].y;
z_NEW[2] += Dpre[i].z;
}
}
num[2]=N-num[0]-num[1];
//printf("%d %d %d \n", num[0], num[1], num[2]);
for(i=0;i<k;i++)
{
x_NEW[i] /= num[i];
y_NEW[i] /= num[i];
z_NEW[i] /= num[i];
sum_co[i]=x_NEW[i]+y_NEW[i]+z_NEW[i];
}
/*for(i=0;i<k;i++)
{
printf("%lf ", sum_co[i]);
}
printf("\n");*/
if(dist_cal(x[0],y[0],z[0],x_NEW[0],y_NEW[0],z_NEW[0])<delta &&
dist_cal(x[1],y[1],z[1],x_NEW[1],y_NEW[1],z_NEW[1])<delta &&
dist_cal(x[2],y[2],z[2],x_NEW[2],y_NEW[2],z_NEW[2])<delta)
{
for(i=0;i<k;i++)
{
if(sum_co[i]==*min_element(sum_co,sum_co+3))
{
printf("The Asia First Class Are:\n");
for(j=0;j<N;j++)
{
if(Dpre[j].Group==i)
printf("%s ", Dpre[j].name);
}
//printf("%lf ", sum_co[i]);
printf("\n");
}
else if(sum_co[i]==*max_element(sum_co,sum_co+3))
{
printf("The Asia Third Class Are:\n");
for(j=0;j<N;j++)
{
if(Dpre[j].Group==i)
printf("%s ", Dpre[j].name);
}
//printf("%lf ", sum_co[i]);
printf("\n");
}
else
{
printf("The Asia Second Classs Are:\n");
for(j=0;j<N;j++)
{
if(Dpre[j].Group==i)
printf("%s ", Dpre[j].name);
}
//printf("%lf ", sum_co[i]);
printf("\n");
}
}
}
else
Code_iteration(x_NEW,y_NEW,z_NEW,k);
}
double dist_cal(double x1, double y1, double z1, double x2, double y2, double z2)
{
double dist;
dist = sqrt(pow(x1-x2,2)+pow(y1-y2,2)+pow(z1-z2,2));
return dist;
}
由于初始点的选择是随机的,由于本身数据的原因和lz代码的不健全性,所以结果会不稳定,因此挑选了一个相对较好的结果:
ps:
当时做实验时对文件读入情有独钟,故基本上数据读入都是文件操作
总结
以上是我大二一门实验课的部分实验内容及结果,有些代码是借鉴别的大佬的,由于时间过久,不知原帖在何处,如有了解的烦请告知。