T1:Gram_ham实现凸包算法:
(1)思路:
(2)代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<stack>
using namespace std;
//备注:这里把 顶点 用 一棵树tree 来形象化的表示,没啥别的意思。。。
//函数声明:
vector<vector<int>> outerTrees(vector<vector<int>> &trees); // 返回 一个二维数组,就是最终的凸包节点次序
int cross(const vector<int> & p, const vector<int> & q, const vector<int> & r);//计算 极角
int distance(const vector<int> & p, const vector<int> & q); //计算2点之间的距离平方
int main()
{
//只需要求一个 凸包
//处理输入:
int T;
cout << "请输入需要测试的 次数: " << endl;
cin >> T; //测试次数
while (T--)
{
cout << "请输入节点个数 :" << endl;
int n; // 有n个 顶点
cin >> n;
vector<vector<int>> trees(n, vector<int>(2, 0));
for (int i = 0; i < n; i++)
{
cout << "请输入第" << i+1 << "个坐标: ";
cin >> trees[i][0] >> trees[i][1]; //得到坐标点(x,y)
}
//(1)计算凸包的 调用 outerTreees函数,得到一个二维数组,其中存储了 凸包的节点次序的二维数组
vector<vector<int>> vec = outerTrees(trees);
//(2)输出凸包的顶点次序:
int size = vec.size();
cout << "这个凸包的 顶点坐标 次序如下: " << endl;
for (int i = 0; i <= size - 1; i++)
{
cout << "(" << vec[i][0] << "," << vec[i][1] << ")" << " ";
}
cout << endl;
}
return 0;
}
vector<vector<int>> outerTrees(vector<vector<int>> &trees) {
int n = trees.size();
if (n < 4) {
return trees;
}
int bottom = 0;
//找到 y 最小的点 bottom
for (int i = 0; i < n; i++) {
if (trees[i][1] < trees[bottom][1]) {
bottom = i;
}
}
swap(trees[bottom], trees[0]);
//以 bottom 原点,按照极坐标的角度大小进行排序
sort(trees.begin() + 1, trees.end(), [&](const vector<int> & a, const vector<int> & b) {
int diff = cross(trees[0], a, b);
if (diff == 0) {
return distance(trees[0], a) < distance(trees[0], b);
}
else {
return diff > 0;
}
});
//对于凸包最后且在同一条直线的元素按照距离从大到小进行排序
int r = n - 1;
while (r >= 0 && cross(trees[0], trees[n - 1], trees[r]) == 0) {
r--;
}
for (int l = r + 1, h = n - 1; l < h; l++, h--) {
swap(trees[l], trees[h]);
}
stack<int> st;
st.emplace(0);
st.emplace(1);
for (int i = 2; i < n; i++) {
int top = st.top();
st.pop();
//如果当前元素与栈顶的两个元素构成的向量顺时针旋转,则弹出栈顶元素
while (!st.empty() && cross(trees[st.top()], trees[top], trees[i]) < 0) {
top = st.top();
st.pop();
}
st.emplace(top);
st.emplace(i);
}
vector<vector<int>> res;
while (!st.empty()) {
res.emplace_back(trees[st.top()]);
st.pop();
}
return res;
}
int cross(const vector<int> & p, const vector<int> & q, const vector<int> & r) {
return (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
}
int distance(const vector<int> & p, const vector<int> & q) {
return (p[0] - q[0]) * (p[0] - q[0]) + (p[1] - q[1]) * (p[1] - q[1]);
}
T2:利用递归 —— 实现 输出杨辉三角的 第i行的 所有 元素:
(1)思路:
<1>递归之处:第i行的第j个元素 = 第i-1行的第j-1个元素 + 第i-1行的第j个元素
<2>所有的递归,都会有出口,比如这里:第1行 或者 第i行的第1列 或者 第i行的最后一列 这些元素的值就是 "1",不能再相深层递归了
(2)代码:
#include<iostream>
using namespace std;
//利用 递归 实现输出 杨辉三角的 第i行数据
int data_i_j(int i, int j) //作用:递归 返回 第i行 ,第j列的 元素
{
//(0)出口:
if (i == 1 || j == 1 || j == i) //第1行 或者 第i行的第1列 或者 第i行的最后一列
{
return 1;
}
//(1)向上面一层递归:
return data_i_j(i - 1, j - 1) + data_i_j(i - 1, j);
}
int main()
{
int T;
cout << "请输入需要测试的 次数 :" << endl;
cin >> T;
while (T--)
{
cout << "请输入 第几行 : " << endl;
int i;
cin >> i;
//输出 第i行的 所有 杨辉三角 元素:
for (int j = 1; j <= i; j++)
{
cout << data_i_j(i, j) << " ";
}
cout << endl;
}
return 0;
}
T3:利用双向链表存储 学生的信息:
(1)思路:
<1>结构体NODE: 数据 + pre指针 + next指针
结构体LIST: Head指针 + Tail指针 + size节点个数(不包含head 和 tail)
<2>可以在 结构体外面写 一个函数给 LIST进行初始化, 也可以 就在里面写一个 构造函数,效果是一样的,这是必须的,因为:
第一:初始的2个指针如果不开辟空间,就是NULL指针,用了就报错
第二:双向链表初始结构就是 head 和 tail的相互指向,需要初始设置这一步
<3>至于 添加 和 删除 节点: 无非就是 修改指针域 罢了
(2)代码:
#include<iostream>
#include<string>
using namespace std;
//实现双端环形链表 结构
//环形结构比较 容易实现 , 只要保证 第一个节点 最后一个节点相互指向就可以了
int MaxNum = 1000; //最大容量
//节点数据结构
typedef struct node
{
int Id; //学号
string name; //姓名
struct node* Pre;//上一节点
struct node* Next;//下一节点
}NODE, *PNODE;
//双向链表数结构
typedef struct List
{
NODE* pHead;//链表头指针
NODE* pTail;//链表尾指针
int size; //当前节点的 数量
//默认构造函数:
List()
{
this->size = 0;
//防止使用空指针:在堆上创建2个指针给head和tail比较好
pHead = new NODE;
pTail = new NODE;
//初始的循环双向链表结构
pHead->Next = pTail;
pHead->Pre = pTail; //这个不动
pTail->Pre = pHead;
pTail->Next = pHead; //这个不动
}
}LIST;
//定义2个函数:
int newStudent(List &L, int stu_id, string stu_name)
{
//(0)检查是否达到人数的上限:
if (L.size == MaxNum)
{
return L.size; //不能添加了。。。
}
//(1)创建一个 新的node*节点,具有id数据,并且 加入到L队列的末尾
NODE* new_node = new NODE;
new_node->Id = stu_id;
new_node->name = stu_name;
//--以下更新4个指针域:
new_node->Next = L.pTail;
new_node->Pre = L.pTail->Pre;
L.pTail->Pre->Next = new_node;//成功insert一个节点
//更新 pTail的pre指针
L.pTail->Pre = new_node; //这4步的指针修改次序不能乱!!!
//更新size 并且返回
L.size++;
return L.size;
}
int delStudent(List& L, int stu_id)
{
//从前向后遍历 —— 找到具有 这个 id的 节点,然后 删除节点
//如果没有找到,就不用任何操作:
NODE* tmp = L.pHead->Next;
while (tmp != L.pTail)
{
if (tmp->Id == stu_id)
{
//删除当前节点,只要修改 前一个节点的next 和 后一个节点的pre就行
tmp->Pre->Next = tmp->Next;
tmp->Next->Pre = tmp->Pre;
//--
L.size--;
delete tmp;
break;
}
//--
tmp = tmp->Next;
}
return L.size;
}
int main()
{
List stuList;
int cnt = 0;
//(1)循环测试 : 添加1-10号学生
for (int i = 1; i <= 10; i++)
{
char ch = 'a' + i;
string str = "Xi_model_";
str = str + ch;
cnt = newStudent(stuList, i , str);
}
cout << "当前学生人数 :" << cnt << endl;
//(2)删除2,3号学生
cnt = delStudent(stuList, 2);
cnt = delStudent(stuList, 3);
cout << "当前学生人数 :" << cnt << endl;
//(3)遍历stuList
NODE* tmp = stuList.pHead->Next;
while (tmp != stuList.pTail)
{
cout << tmp->Id << " " << tmp->name << endl;;
tmp = tmp->Next;
}
cout << endl;
return 0;
}