1、凯撒密码
1、初步搭建框架
string input()//用户输入明文
{
string plaintext;
cout << "请输入明文:" << endl;
cin >> plaintext;
return plaintext;
}
2、如何计算字符串长度
目的:作为循环条件
解决:string库中包含计算字符串长度函数
用法:
string plaintext;
int num;
num = plaintext.size();
经过多次思考,没有必要计算字符串长度
for (i = 0; plaintext[i] != 0; i++)
{ }
3、将明文转换为一串数字
4、设计密文生成算法
for (i = 0; a[i] != 0; i++)
{
if (a[i] > 64 && a[i] < 91)//如果是大写字母
{
if (a[i] + num < 65)
b[i] = a[i] + num +26;
else if (a[i] + num >= 65 && a[i] + num <= 90)
b[i] = a[i] + num;
else
b[i] = a[i] + num - 26;
}
else if (a[i] > 96 && a[i] < 123)//如果是小写字母
{
if (a[i] + num < 97)
b[i] = a[i] + num + 26;
else if (a[i] + num >= 97 && a[i] + num <= 122)
b[i] = a[i] + num;
else
b[i] = a[i] + num - 26;
}
}
5、最终成果
#include<iostream>
#include<string>
using namespace std;
string input()//用户输入明文
{
string plaintext;
cout << "请输入明文:" << endl;
cin >> plaintext;
return plaintext;
}
void key(string plaintext)//形成密文,并输出
{
int i;
int num = 0;
int a[1000] = { 0 };//明文
int b[1000] = { 0 };//密文
for (i = 0; plaintext[i] != 0; i++)//将明文转化为一个由ASCⅡ表对应数字的数组
{
a[i] = (int)plaintext[i];
}
cout << "请输入您想位移的数字:(正数—右移,负数—左移)" << endl;
cin >> num;
for (i = 0; a[i] != 0; i++)
{
if (a[i] > 64 && a[i] < 91)//如果是大写字母
{
if (a[i] + num < 65)
b[i] = a[i] + num +26;
else if (a[i] + num >= 65 && a[i] + num <= 90)
b[i] = a[i] + num;
else
b[i] = a[i] + num - 26;
}
else if (a[i] > 96 && a[i] < 123)//如果是小写字母
{
if (a[i] + num < 97)
b[i] = a[i] + num + 26;
else if (a[i] + num >= 97 && a[i] + num <= 122)
b[i] = a[i] + num;
else
b[i] = a[i] + num - 26;
}
}
cout << "密文为:";
for (i = 0; b[i] != 0; i++)
cout << (char)b[i] ;
cout << "\n";
}
int main()
{
string plaintext;
int i;
plaintext = input();//输入明文
key(plaintext);
system("pause");
return 0;
}
6、测试
任务文件中示例
2、关键字密码
1、初步搭建框架
这个框架仅为初步搭建,后期的编写中再次对框架进行修改,但解决问题的流程大致没变
本次编写是我首次运用了面向对象的方法,对方法进行了封装
2、class中的属性
3、生成密码表
4、将明文转化为密文
5、最终成果
#include<iostream>
#include<string>
using namespace std;
class KeyWord_class
{
public:
//方法
void input(string plaintext)//用户输入明文
{
int i;
for (i = 0; (int)plaintext[i] != 0; i++)
m_Plaintext[i] = (int)plaintext[i];//将字符转换为数字
}
void keyword(string keyword)//用户输入关键字
{
m_keyword = keyword;
}
void turn01(string keyword)//生成密码表
{
int i, j;//循环变量
int s = 0;//状态变量,1—存在,0—不存在
int letter = 0;
int list[26] = { 0 };//存放字母表的整形数组
int num = keyword.size();
for (i = 0; i < num; i++)
{
list[i] = (int)keyword[i];//先把关键字转换为数字形式放入字母表
}
letter = list[num - 1] + 1;
for (i = num; i < 26; i++)//接着关键字继续放入其余字母
{
for (j = 0; j < num; j++)//依次查看关键字中每个字母
{
if (list[j] == letter)//如果已经存在该字母,使s变为1
{
s = 1;
}
}
if (s == 1)
i--;
else//如果不存在该字母,接着关键字放入字母
{
if (letter > 90)//如果超过Z,从A开始
letter = 65;
list[i] = letter;
}
letter++;
s = 0;//重置状态变量
}
for (i = 0; i < 26; i++)//放入字母表
{
m_list[i] = list[i];
}
}
void turn02()//将明文转换为密文
{
int i, j;
for (i = 0; m_Plaintext[i] != 0; i++)//依次在明文中遍历
{
for (j = 0; j < 26; j++)//在字母表中查找
{
if (m_Plaintext[i] - 65 == j)
{
m_ciphertext[i] = m_list[j];
}
}
}
}
void output01(int list[26])
{
int i;
for (i = 0; i < 26; i++)
{
cout << (char)list[i];
}
cout << "\n";
}
void output()
{
int i;
for (i = 0; m_ciphertext[i] != 0; i++)
{
cout << (char)m_ciphertext[i];
}
cout << "\n";
}
private:
//属性
int m_Plaintext[1000] = { 0 };//明文
string m_keyword;//关键字
int m_list[26] = { 0 };//字母表
int m_ciphertext[1000] = { 0 };//密文
};
int main()
{
KeyWord_class k;//创建一个对象,类的实例化
string plaintext;
string keyword;
//输入明文
cout << "请输入明文(大写字母):" << endl;
cin >> plaintext;
k.input(plaintext);
//输入关键字
cout << "请输入关键字:" << endl;
cin >> keyword;
k.keyword(keyword);
//生成字母表
k.turn01(keyword);
//明文转化为密文
k.turn02();
//输出密文
cout << "输出密文:" << endl;
k.output();
system("pause");
return 0;
}
6、测试
3、纵栏式移项密码
1、框架
2、对关键字排序
void sort()//对关键字排序
{
int m, n;
int i, j;
int a[10] = { 0 };
for (i = 0; i < 10; i++)//对关键字排序
{
for (m = 0, n = 1; n < 10; n++)//m为这个数组中最大元素
{
if (m_keyword[m] < m_keyword[n])
m = n;
}
a[i] = (m == m_num - 1 ? 0 : m + 1);
m_keyword[m] = 0;
}
for (i = m_num - 1, j = 0; i > -1; i--, j++)//将密码表内数字按从小到大的顺序放入
{
m_keyword[j] = a[i];
}
}
3、将明文转化为密文
void turn()//将明文转化为密文
{
int i, j, k = 0;
for (i = 0; i < m_num; i++)
{
for (j = 0; m_plaintext[j] != 0; j++)
{
if ((j + 4) % m_num == m_keyword[i])
{
m_ciphertext[k] = m_plaintext[j];
k++;
}
}
}
}
这里的难点主要是需要搞清楚每个变量所代表的含义
4、最终成果
#include<iostream>
#include<string>
using namespace std;
class column
{
public:
void input(string plaintext)//输入明文,并转换为数字
{
int i;
for (i = 0; plaintext[i] != 0; i++)
{
m_plaintext[i] = plaintext[i];
}
}
void put_keyword(string keyword)//输入关键字,并转化为数字
{
int i;
m_num = keyword.size();
if (m_num > 11)
return;
for (i = 0; keyword[i] != 0; i++)
{
m_keyword[i] = keyword[i];
}
}
void sort()//对关键字排序
{
int m, n;
int i, j;
int a[10] = { 0 };
for (i = 0; i < 10; i++)//对关键字排序
{
for (m = 0, n = 1; n < 10; n++)//m为这个数组中最大元素
{
if (m_keyword[m] < m_keyword[n])
m = n;
}
a[i] = (m == m_num - 1 ? 0 : m + 1);
m_keyword[m] = 0;
}
for (i = m_num - 1, j = 0; i > -1; i--, j++)//将密码表内数字按从小到大的顺序放入
{
m_keyword[j] = a[i];
}
}
void turn()//将明文转化为密文
{
int i, j, k = 0;
for (i = 0; i < m_num; i++)
{
for (j = 0; m_plaintext[j] != 0; j++)
{
if ((j + 4) % m_num == m_keyword[i])
{
m_ciphertext[k] = m_plaintext[j];
k++;
}
}
}
}
void output()//输出密文
{
int i;
for (i = 0; m_ciphertext[i] != 0; i++)
{
cout << (char)m_ciphertext[i];
}
cout << "\n";
}
private:
int m_plaintext[1000] = { 0 };//明文
int m_keyword[10] = {0};//关键字
int m_num = 0;//关键字长度
int m_ciphertext[1000] = { 0 };//密文
};
int main()
{
column c;
string plaintext;
string keyword;
cout << "请输入明文(大写字母):" << endl;
cin >> plaintext;
c.input(plaintext);
cout << "请输入关键字(少于10个大写字母):" << endl;
cin >> keyword;
c.put_keyword(keyword);
c.sort();//关键字排序
c.turn();//明文转密文
cout << "密文为:" << endl;//输出密文
c.output();
system("pause");
return 0;
}
5、测试
4、中国式密码
1、框架
2、明文中偶数列逆置
void turn01()//明文中偶数列逆置
{
int s = -1;//状态变量,1—奇,-1—偶
int i, j, k;//循环变量
int item = 0;//中间变量
for (i = 0; m_plaintext[i] != 0; i++)
{
if (i % m_rownum == 0)
{
s *= -1;
}
if (i % m_rownum == 0 && s == -1)
{
for (j = i, k = 1; j < (i + m_rownum - k); j++, k++)
{
item = m_plaintext[j];
m_plaintext[j] = m_plaintext[i + m_rownum - k];
m_plaintext[i + m_rownum - k] = item;
}
}
}
}
3、明文按行放置形成密文
void turn02()//明文按行放置形成密文
{
int i, j, k = 0;
for (i = 1; i < m_rownum; i++)//余数依次增大
{
for (j = m_textnum; j >= 0; j--)
{
if (j % m_rownum == i)
{
m_ciphertext[k++] = m_plaintext[j - 1];
}
}
}
for (j = m_textnum; j >= 0; j--)//整除情况
{
if (j % m_rownum == 0)
m_ciphertext[k++] = m_plaintext[j - 1];
}
}
4、最终成果
#include<iostream>
#include<string>
using namespace std;
class Chinese
{
public:
void input(string plaintext)//输入明文
{
int i;
m_textnum = plaintext.size();
for (i = 0; plaintext[i] != 0; i++)
{
m_plaintext[i] = plaintext[i];
}
}
void input_rownum(int rownum)//输入行数
{
m_rownum = rownum;
}
void turn01()//明文中偶数列逆置
{
int s = -1;//状态变量,1—奇,-1—偶
int i, j, k;//循环变量
int item = 0;//中间变量
for (i = 0; m_plaintext[i] != 0; i++)
{
if (i % m_rownum == 0)
{
s *= -1;
}
if (i % m_rownum == 0 && s == -1)
{
for (j = i, k = 1; j < (i + m_rownum - k); j++, k++)
{
item = m_plaintext[j];
m_plaintext[j] = m_plaintext[i + m_rownum - k];
m_plaintext[i + m_rownum - k] = item;
}
}
}
}
void turn02()//明文按行放置形成密文
{
int i, j, k = 0;
for (i = 1; i < m_rownum; i++)//余数依次增大
{
for (j = m_textnum; j >= 0; j--)
{
if (j % m_rownum == i)
{
m_ciphertext[k++] = m_plaintext[j - 1];
}
}
}
for (j = m_textnum; j >= 0; j--)//整除情况
{
if (j % m_rownum == 0)
m_ciphertext[k++] = m_plaintext[j - 1];
}
}
void output()//输出密文
{
int i;
for (i = 0; m_ciphertext[i] != 0; i++)
{
cout << (char)m_ciphertext[i];
}
cout << "\n";
}
private:
int m_plaintext[1000] = { 0 };
int m_textnum = 0;
int m_rownum = 0;
int m_ciphertext[1000] = { 0 };
};
int main()
{
Chinese c;
string plaintext;
int rownum = 0;
cout << "请输入明文:" << endl;
cin >> plaintext;
c.input(plaintext);
cout << "请输入目标行数:" << endl;
cin >> rownum;
c.input_rownum(rownum);
c.turn01();
c.turn02();
c.output();
system("pause");
return 0;
}
5、测试
5、kNN算法的实现
1、数据集下载
下载地址:http://archive.ics.uci.edu/ml/index.php
选择下载鸢尾花数据集
2、结构体的构造
typedef struct my
{
vector<float> attribute;
string label;
float distance = 0;
}Data;
3、数据集以txt格式输入程序
知识点:C++的文件操作
参考教程:C++文件类(文件流类)及用法详解
[C++:不如Coding](27):文件操作(1):使用文件流简单地读取和写入文件
4、输入函数的实现
1、训练集输入
void input_d(vector<Data>& dataset, int m)
{
int i, j, n = 0;
float item;
string label;
cout << "请输入训练集的大小:" << endl;
cin >> n;
cout << "请输入训练集:" << endl;
for (j = 0; j < n; j++)
{
Data t;
for (i = 0; i < m; i++)
{
cin >> item;
t.attribute.push_back(item);
//dataset.attribute.push_back(item);
}
dataset.push_back(t);
cin >> dataset[j].label;
}
}
测试:
2、测试集输入
void input_t(vector<Data>& testset, int m)
{
int i, j, n = 0;
float item;
cout << "请输入测试集的大小:" << endl;
cin >> n;
cout << "请输入测试集:" << endl;
for (j = 0; j < n; j++)
{
Data t;
for (i = 0; i < m; i++)
{
cin >> item;
t.attribute.push_back(item);
}
testset.push_back(t);
}
}
测试:
5、计算距离函数构造
void distance(vector<Data>& dataset, Data& testset)
{
unsigned int i, j;
for (i = 0; i < dataset.size(); i++)
{
float sum = 0.0;
for (j = 0; j < dataset[i].attribute.size(); j++)
{
sum += (dataset[i].attribute[j] - testset.attribute[j]) * (dataset[i].attribute[j] - testset.attribute[j]);
}
dataset[i].distance = sqrt(sum);
}
}
测试:
6、排序函数构造
排序方法:冒泡排序
void sort(vector<Data>& dataset)
{
unsigned int i, j;
for (i = 0; i < dataset.size(); i++)
{
for (j = i + 1; j < dataset.size(); j++)
{
if (dataset[i].distance > dataset[j].distance)
{
Data item = dataset[i];
dataset[i] = dataset[j];
dataset[j] = item;
}
}
}
}
测试:
7、分类函数构造
void classify(vector<Data>& dataset, Data& testset, int k)
{
int i;
map<string, int> label;
for (i = 0; i < k; i++)
{
label[dataset[i].label]++;
}
int max = label[dataset[0].label];
for (map<string, int>::iterator iter = label.begin(); iter != label.end(); iter++)
{
if (iter->second > max)
{
max = iter->second;
}
//cout << "类别:" << iter->first << "\t次数:" << iter->second << endl;
}
for (map<string, int>::iterator iter = label.begin(); iter != label.end(); iter++)
{
if (iter->second == max)
{
testset.label = iter->first;
}
}
cout << testset.label << endl;
}
测试:
8、最后成果
#include<iostream>
#include<string>
#include<vector>
#include <map>
using namespace std;
typedef struct my
{
vector<float> attribute;
string label;
float distance = 0;
}Data;
void input_d(vector<Data>& dataset, int m)
{
int i, j, n = 0;
float item;
string label;
cout << "请输入训练集的大小:" << endl;
cin >> n;
cout << "请输入训练集:" << endl;
for (j = 0; j < n; j++)
{
Data t;
for (i = 0; i < m; i++)
{
cin >> item;
t.attribute.push_back(item);
//dataset.attribute.push_back(item);
}
dataset.push_back(t);
cin >> dataset[j].label;
}
}
void input_t(vector<Data>& testset, int m)
{
int i, j, n = 0;
float item;
cout << "请输入测试集的大小:" << endl;
cin >> n;
cout << "请输入测试集:" << endl;
for (j = 0; j < n; j++)
{
Data t;
for (i = 0; i < m; i++)
{
cin >> item;
t.attribute.push_back(item);
}
testset.push_back(t);
}
}
void distance(vector<Data>& dataset, Data& testset)
{
unsigned int i, j;
for (i = 0; i < dataset.size(); i++)
{
float sum = 0.0;
for (j = 0; j < dataset[i].attribute.size(); j++)
{
sum += (dataset[i].attribute[j] - testset.attribute[j]) * (dataset[i].attribute[j] - testset.attribute[j]);
}
dataset[i].distance = sqrt(sum);
}
}
void sort(vector<Data>& dataset)
{
unsigned int i, j;
for (i = 0; i < dataset.size(); i++)
{
for (j = i + 1; j < dataset.size(); j++)
{
if (dataset[i].distance > dataset[j].distance)
{
Data item = dataset[i];
dataset[i] = dataset[j];
dataset[j] = item;
}
}
}
}
void classify(vector<Data>& dataset, Data& testset, int k)
{
int i;
map<string, int> label;
for (i = 0; i < k; i++)
{
label[dataset[i].label]++;
}
int max = label[dataset[0].label];
for (map<string, int>::iterator iter = label.begin(); iter != label.end(); iter++)
{
if (iter->second > max)
{
max = iter->second;
}
//cout << "类别:" << iter->first << "\t次数:" << iter->second << endl;
}
for (map<string, int>::iterator iter = label.begin(); iter != label.end(); iter++)
{
if (iter->second == max)
{
testset.label = iter->first;
}
}
cout << testset.label << endl;
}
int main()
{
unsigned int i;
int k = 0;
int m = 0;//数据属性的维数
vector<Data> dataset;
vector<Data> testset;
cout << "请输入数据属性的维数:" << endl;
cin >> m;
input_d(dataset, m);//输入训练集
input_t(testset, m);//输入测试集
cout << "输入您期望的k值:" << endl;//输入k值
cin >> k;
for (i = 0; i < testset.size(); i++)
{
distance(dataset, testset[i]);//计算每个测试数据与每个训练数据的距离
sort(dataset);//升序排序
classify(dataset, testset[i], k);
}
system("pause");
return 0;
}
测试:
9、输入函数重新设计(文件流形式)
1、训练集输入
void input_d(vector<Data>& dataset, int n)
{
int i, j, size = 0;
float item;
ifstream asd;
cout << "请输入训练集的大小:" << endl;
cin >> size;
asd.open("iris_train.txt");
if (!asd.is_open())
{
cout << "打开文件失败!" << endl;
return;
}
for (j = 0; j < size; j++)
{
Data t;
//asd >> t.label;
for (i = 0; i < n; i++)
{
asd >> item;
t.attribute.push_back(item);
}
asd >> t.label;
dataset.push_back(t);
}
asd.close();
//output(dataset, size, n);
}
2、测试集输入
void input_t(vector<Data>& dataset, int n)
{
int i, j, size = 0;
float item;
ifstream asd;
cout << "请输入测试集的大小:" << endl;
cin >> size;
asd.open("iris_test.txt");
if (!asd.is_open())
{
cout << "打开文件失败!" << endl;
return;
}
for (j = 0; j < size; j++)
{
Data t;
for (i = 0; i < n; i++)
{
asd >> item;
t.attribute.push_back(item);
}
dataset.push_back(t);
}
asd.close();
//output(dataset, size, n);
}
好处:简化输入步骤,方便大型数据集的输入
10、其他数据集的测试
测试数据集:鲍鱼、葡萄酒
下图为针对葡萄酒数据集,计算距离函数的修改
结果:
6、收获
1、智能指针
- what:
C++新标准库提供了智能指针来管理动态对象,它的行为类似于常规指针,重要的区别是它能够自动释放所指向对象的空间,并且它是封装好的模板类- why:
为了安全方便地使用动态内存,管理动态内存的开辟与释放,避免内存泄露。- how:
智能指针分为四种:auto_ptr、shared_ptr、unique_ptr、weak_ptr
unique_ptr
初始化方法
方法一:
std::unique_ptr<类型> p1(new 类型(值));方法二:
std::unique_ptr<类型> p1
p1.reset(new 类型(值));
2、封装
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
语法:class 类名{ 访问权限: 属性/行为};
访问权限:
- 公共权限:public 类内可以访问 类外可以访问
- 保护权限:protected 类内可以访问 类外不可以访问
- 私有权限:private 类内可以访问 类外不可以访问
3、C++ 文件和流
数据类型 | 描述 |
---|---|
ofstream | 该数据类型表示输出文件流,用于创建文件并向文件写入信息。 |
ifstream | 该数据类型表示输入文件流,用于从文件读取信息。 |
fstream | 该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。 |
打开文件
基础语法:
void open(const char *filename, ios::openmode mode);
在这里,open() 成员函数的第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。
模式标志 | 描述 |
---|---|
ios::app | 追加模式。所有写入都追加到文件末尾。 |
ios::ate | 文件打开后定位到文件末尾。 |
ios::in | 打开文件用于读取。 |
ios::out | 打开文件用于写入。 |
ios::trunc | 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。 |
关闭文件
基础语法:
void close();
写入文件
在 C++ 编程中,我们使用流插入运算符( << )向文件写入信息,就像使用该运算符输出信息到屏幕上一样。唯一不同的是,在这里您使用的是 ofstream 或 fstream 对象,而不是 cout 对象。
读取文件
在 C++ 编程中,我们使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。唯一不同的是,在这里您使用的是 ifstream 或 fstream 对象,而不是 cin 对象。
4、vector容器的使用
构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin() , v.end( ));//将v[begin(), end())区间中的元素拷贝给本身
vector(n,elem); //构造函数将n个elem拷贝给本身。
vector( const vector &vec) ; //拷贝构造函数。
插入函数
push_back(ele);//尾部插入元素ele
pop_back() ;//删除最后一个元素
insert(const_iterator pos, ele);//迭代器指向位置pos插入元素ele
insert(const_iterator pos,int count,ele);//迭代器指向位置pos插入count个元素
erase(const_iterator pos ) ;//册除迭代器指向的元素
erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素clear();
clear();//册除容器中所有元素
5、map容器的使用
简介:
- map中所有元素都是pair
- pair中第一个元素为key(键值),起到索引作期,第二个元素为value (实值)
- 所有元素都会根据元素的键值自动排序
用途:提供一对一的映射矢系
构造函数
map<T1,T2> mp; //map默认构造函数:
map(const map &mp ) ; //拷贝构造函数
插入函数
//第一种
m. insert(pair<int,int>(1,10) ) ;
//第二种
m. insert (make_pair(2,20) ) ;
//第三种
m.insert (map<int, int> : : value_type(3,30) ) ;
//第四种
m[4] = 40;