使用Visual Studio community 2022运行。

//虽然写起来还是比较慢的,但是,比起从头开始写快很多了。
//kruskal算法就一点点
//所以,我认为,在完成基本要求后,对于一段代码,如果可能的话,那就仔细探究这段代码的通用性,严格检查其错误,
//让这段代码变成可以快速复制到别的地方的代码。
#include <iostream>
#include <limits>
#include <memory>
#include <stdlib.h>
#include <string>
#include <vector>
using namespace std;
//我要建立一个堆结构,这个堆随本程序运行而建立,随本程序结束而消失,(或者把控制权给别的程序)。
// 这个堆不能进行复制,只能进行创建,修改,交权,删除。
// 我觉得,堆是给数字排序的,但是仅仅给数字排序没有意义。 需要给数字和某种数据类型建立联系。//所以参与建立堆的数据类型是带有明确的可比较的数(比如正整数)的数据类型。
// 但是我想把程序写成泛型的。 因为只要带有课比较的数的数据类型都可以建立堆。
// 我不会这样写代码。 可能这需要c++ 的泛型技术或者c里面强制更改指针类型
// 我暂时不会那样写代码。我的代码要有通用性,至少做到可以把大段代码复制过去,改改就能用于新的类型。
//是不是在数据结构这门课上写通用代码不合适啊,有专门熟悉一门编程语言的课或者书。
//Task 是通用的数据类型typedef struct Edge Task;
//Finger的设计目的是作为堆的元素,使堆能控制int类型以外的数据。
//因为Finger是个对象,而教材上给的只是个整形,所以要给Finger加许多操作。
struct Finger
{Finger(int c1, Task* c2) :P(c1), t(c2) {}
Finger() = default;
Finger(const Finger& f) :P(f.P), t(f.t) {}int P;
Task* t;
//埋下隐患1 这里只给Finger的P赋值优先级
Finger& operator=(const int& i)
{P = i;
return *this;
}
Finger& operator=(const Finger& f) {P = f.P;
t = f.t;
return *this;
}
};
//重载了Finger的六个关系运算符。
bool operator< (const Finger& h1, const Finger& h2)
{return h1.P < h2.P;
}
bool operator<= (const Finger& h1, const Finger& h2)
{return h1.P <= h2.P;
}
bool operator> (const Finger& h1, const Finger& h2)
{return h1.P > h2.P;
}
bool operator>= (const Finger& h1, const Finger& h2)
{return h1.P >= h2.P;
}
bool operator== (const Finger& h1, const Finger& h2)
{return h1.P == h2.P;
}
bool operator!= (const Finger& h1, const Finger& h2)
{return h1.P != h2.P;
}//struct Edge是Kruskal算法需要使用的类型。Edge将被构造,Finger类型指向Edge,Finger类型是堆的元素。
//Edge最后被放入vector中,作为结果。
typedef int Vertex;
struct Edge {Vertex v1;Vertex v2;int Weight;Edge() = default;Edge(const Edge& e1) {v1 = e1.v1;v2 = e1.v2;Weight = e1.Weight;}
};
Edge* NewEdge(Vertex v1,Vertex v2,int Weight)
{//学号不检查,默认为可以为0或负数Edge* e = new Edge;e->v1 = v1;e->v2 = v2;e->Weight = Weight; return e;
}
bool operator==(const Edge& e1, const Edge& e2)
{if (e1.Weight != e1.Weight) return false;if (e1.v1 == e2.v1 && e1.v2 == e2.v2|| e1.v1 == e2.v2 && e2.v1 == e1.v2)return true;
}typedef struct HNode* Heap; /* 堆的类型定义 */
typedef Finger ElementType;/*Finger是堆的元素,该元素能指向其他类型*/
struct HNode {ElementType* Data; /* 存储元素的数组 */
int Size; /* 堆中当前元素个数 */
int Capacity; /* 堆的最大容量 */
};
typedef Heap MaxHeap; /* 最大堆 */
typedef Heap MinHeap; /* 最小堆 */
#define MAXDATA 10000 /* 该值应根据具体情况定义为大于堆中所有可能元素的值 */
#define MINDATA -10000
MinHeap CreateHeap(int MaxSize)
{ /* 创建容量为MaxSize的空的最小堆 */MinHeap H = (MinHeap)malloc(sizeof(struct HNode));
H->Data = (ElementType*)malloc((MaxSize + 1) * sizeof(ElementType));
H->Size = 0;
H->Capacity = MaxSize;
H->Data[0] =ElementType(-10000,NULL); /* 定义"哨兵"为x小于堆中所有可能元素的值*/
// 我 我为这个操作重载了=
return H;
}
bool IsFull(MinHeap H)
{return (H->Size == H->Capacity);
}
bool IsEmptyH(MinHeap H) {return H->Size == 0;
}
bool Insert(MinHeap H, ElementType X)
{ /* 将元素X插入最小堆H,其中H->Data[0]已经定义为哨兵 */
int i;if (IsFull(H)) {printf("最小堆已满");
return false;
}
i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */
for (; H->Data[i / 2] > X; i /= 2)
H->Data[i] = H->Data[i / 2]; /* 上滤X */
H->Data[i] = X; /* 将X插入 */
return true;
}
ElementType DelRoot(MinHeap H)
{//这个操作不管没有第0项的bug;if (IsEmptyH(H)) {printf("MinHeap is Empty\n");return H->Data[0];}ElementType anwser = H->Data[1];/* 用最xiao堆中最后一个元素从根结点开始向上过滤下层结点 */ElementType X = H->Data[H->Size--]; /* 注意当前堆的规模要减小 */int Parent, Child;for (Parent = 1; Parent * 2 <= H->Size; Parent = Child) {Child = Parent * 2;if ((Child != H->Size) && (H->Data[Child].P > H->Data[Child + 1].P))Child++;  /* Child指向左右子结点的较xiao者 */if (X.P <= H->Data[Child].P) break; /* 找到了合适位置 */else  /* 下滤X */H->Data[Parent] = H->Data[Child];}H->Data[Parent] = X;return anwser;
}//20210820我要做的是简单的并查集合,只有合并和查找操作。
//用数组实现,
//数组的元素应该是个结构啊,老师给的代码怎么没有呢
//看不懂老师给的代码
//她可能给的是那个最简表示法,不要数据,既然不要数据,
//那就不应该有ElementType
//我很难看懂老师的通用化操作,以及她为了教学而简化的各种细节,
// 实际上 复杂一点反而更容易懂
//我首先不要直接追求通用化,我首先应该最求把数据结构和算法写出来,
//直接用int写最好。
/*20210906写非最简版本
*/
//我要更改Element为我需要的类型Edge
//我弄错了,并查集要存的是顶点,而不是边。两个顶点都入了集,就回路了。
/*这个并查集的Node元素的设计似乎没必要。它的Element类型没什么运用。它的功能过于简单,如果要追究它的元素应该倒过来
* 让别的数据指向这个并查集的元素。
*/
struct Node
{int Root = -1;int Element = 0;Node() = default;Node(int i1, int i2) :Root(i1), Element(i2) {}
};
int GoToRoot(int X, const vector<Node>& s1)
{//检查该元素是否在该集合内,因为是0~size-1与实体对应的集合,所以比较两个//特殊数据就可以了if (X > -1 && X < s1.size()){if (s1[X].Root < 0) return X;elsereturn GoToRoot(s1[X].Root, s1);}elsereturn -1;
}
int FindElement(int X, const vector<Node>& s1)
{//函数名不好,实际上是找到该元素的根的位置。for (int i = 0; i != s1.size(); ++i)if (s1[i].Element == X)return GoToRoot(i, s1);return -1;
}
void UnionRoot(vector<Node>& S, int Root1, int Root2)
{ /* 这里默认Root1和Root2是不同集合的根结点 *//* 保证小集合并入大集合 */if (S[Root2].Root < S[Root1].Root) { /* 如果集合2比较大 */S[Root2].Root += S[Root1].Root;     /* 集合1并入集合2  */S[Root1].Root = Root2;}else {                         /* 如果集合1比较大 */S[Root1].Root += S[Root2].Root;     /* 集合2并入集合1  */S[Root2].Root = Root1;}
}
//bool Union(vector<Node>& S, int X1, int X2)
//{//    auto r1 = FindElement(X1, S);
//    auto r2 = FindElement(X2, S);
//    auto Same = r1 == r2;
//    if (!Same)
//        UnionRoot(S, r1, r2);
//    return Same;
//}
bool Union2(vector<Node>& S, int X1, int X2)
{auto r1 = GoToRoot(X1, S);auto r2 = GoToRoot(X2, S);auto Same = r1 == r2;if (!Same)UnionRoot(S, r1, r2);return Same;
}//用邻接表存储 you权有向图。
//所以要复习一遍邻接表的构造。
//如果你要用到邻接表,你又会发现,你好像只能用动态内存来存 出 或 入 的数组。
// 我的邻接链表是出度和入度都有的。
//当你要表示有权图的时候,是不是要把权重写道listnode里面呢?有没有别的办法?
//这样权重被存储了两次。出一次,入一次。
//更新:本次要用于kruskal算法,这个算法对无向图才有效,所以,要在buildgraph上建立有向图。
//如果要提高效率,那么不应该区分出度和入度,只用一个度就够了。否则就太浪费了。
//所以,在构建Edge时只用一半就行了。struct ListNode
{int vertex;int weight;struct ListNode* next;
};
struct Adjacency_List {int vertex_N;struct ListNode** point_me;struct ListNode** point_other;
};
typedef int Vertex;
struct Adjacency_List* set_vertex_N(struct Adjacency_List* pa, int n)
{//无检查,默认你输入的全部正确;//你可以检查一下,whether pa所指向的Adjacency_List had been initialized or whether n more than 0;//I just ignore it.//这个函数就是分配两个数组,数组里存指针,指针是链表头,pa->vertex_N = n;pa->point_me = (struct ListNode**)malloc(sizeof(struct ListNode*) * n);pa->point_other = (struct ListNode**)malloc(sizeof(struct ListNode*) * n);//因为是初始化,所以,我要清理一下,让上述数组的每个元素都是NULLfor (int i = 0; i != n; ++i){pa->point_me[i] = NULL;pa->point_other[i] = NULL;}return pa;
}
struct Adjacency_List* insert_edge(struct Adjacency_List* const pa, int vertex1, int vertex2, int weight) {//vertex1----> vertex2struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));temp->vertex = vertex1;temp->next = pa->point_me[vertex2];temp->weight = weight;pa->point_me[vertex2] = temp;temp = (struct ListNode*)malloc(sizeof(struct ListNode));temp->vertex = vertex2;temp->next = pa->point_other[vertex1];temp->weight = weight;pa->point_other[vertex1] = temp;return pa;
}void build_graph_AC(struct Adjacency_List* pa)
{/*这是一个无向图版本,实际上它还是有图,只不过,正反各insert一次*/int vertexN;puts("输入顶点数");scanf_s("%d", &vertexN);set_vertex_N(pa, vertexN);puts("输入vertex1 <----> vertex2,  权重,\n示例:0 2 100\n输入三个负数结束\n示例:-1 -1 -1");int vertex1, vertex2, weight;scanf_s("%d %d %d", &vertex1, &vertex2, &weight);while (vertex1 >= 0) {insert_edge(pa, vertex1, vertex2, weight);insert_edge(pa, vertex2, vertex1, weight);scanf_s("%d %d %d", &vertex1, &vertex2, &weight);}
}//struct TwoIntP {//    /*用于保存结果*/
//    int* p1;
//    int  size1;
//    int* p2;
//    int  size2;
//};//void show_distance_or_path(int d[], int n) {//    for (int i = 0; i < n; ++i) {//        printf("%d  ", d[i]);
//    }
//    printf("\n");
//}vector<Edge> Kruskal(const struct Adjacency_List& g)
{MinHeap H=CreateHeap(g.vertex_N*(g.vertex_N-1)/2);for (int i = 0; i != g.vertex_N; ++i){auto* po = g.point_other[i];while (po){auto v2 = po->vertex;if (v2>i)/*避免Graph的来回指向的冗余*/{Edge* ep = NewEdge(i, v2, po->weight);Insert(H, Finger(po->weight, ep));}po = po->next;}}vector<Node> vn;vn.resize(g.vertex_N);vector<Edge> ve;do{Edge e1=*(DelRoot(H).t);if (GoToRoot(e1.v1, vn) != GoToRoot(e1.v2, vn)){ve.push_back(e1);Union2(vn, e1.v1, e1.v2);}} while (ve.size() < static_cast<unsigned long long>(g.vertex_N) - 1 && !IsEmptyH(H));if (ve.size() < g.vertex_N - 1){cerr << "ERROR:这个图不连通!" << endl;}return ve;
}int main()
{struct Adjacency_List* pa = new Adjacency_List;build_graph_AC(pa);vector<Edge> ve = Kruskal(*pa);for (const auto& c : ve){cout << "(" << c.v1 << " , " << c.v2 << ")" << "  ______路程: " << c.Weight << endl;}}

Kruskal算法 数据结构 浙江大学 陈越、何钦铭相关推荐

  1. 数据结构-第一讲 基本概念-学习笔记(MOOC 浙江大学 陈越 何钦铭)

    目录 第一讲 基本概念 1.1 什么是数据结构 1.1.1 关于数据组织 - 例:图书摆放 1.1.2 关于空间使用 - 例:PrintN函数实现 1.1.3 关于算法效率 - 例:计算多项式值 计算 ...

  2. C语言实现Prim算法与Kruskal算法(浙大 陈越版)

    案例6-1.7 公路村村通 (30分) 现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本. 输入格式: 输入数据包括城镇数目正整数N ...

  3. 浙江大学计算机学院何钦铭,浙江大学导师介绍--何钦铭

    个人简介 何钦铭,男,教授,博士生导师,浙江大学国家示范性软件学院副院长.计算机学院副院长.教育部理工科计算机基础课程教学指导分委会委员.浙江省计算机专业教学指导委员会主任委员.浙江省计算机教育研究会 ...

  4. 浙江大学陈越教授数据结构PTA 题目——最大子列和(在线处理法)

    注意: 1.数组的循环输入要取地址!!!!! for(int i=0;i<K;i++)     {         scanf("%d",&a[i]);     // ...

  5. 《数据结构》陈越课件重点总结

    一  概述 空间复杂度S(n) -- 根据算法写成的程序在执行时占用存储单元的长度. 时间复杂度T(n) -- 根据算法写成的程序在执行时耗费时间的长度.

  6. 《数据结构》陈越——习题及解析二

    二叉树及存储结构 解析: 解析:总共有六层,最大结点树为2^6-1=63,这是对于完美二叉树来说的,但是由于其第六层节点数为8,不为2^(i-1),i为第i层的序号i,即不为2^(6-1)=32,故不 ...

  7. 数据结构(陈越、何钦铭)学习笔记

    本系列文章为浙江大学陈越.何钦铭数据结构学习笔记,系列文章链接如下: 文章目录 一.基本概念 二.线性结构 三.树 四.图 五.排序 六.散列查找 一.基本概念 数据结构基础:P1-基本概念 数据结构 ...

  8. 数据结构与算法(陈越)(学习笔记)(更新ing)

    数据结构(陈越) 一.数据结构(计算运行时间) #include<stdio.h> #include<time.h> #include<math.h> clock_ ...

  9. 数据结构浙江大学 全部思考题+每周练习答案(已完结)

    全部每周作业和视频思考题答案和解析 见 浙江大学 数据结构 思考题+每周练习答案 MOOC上浙江大学陈越和何钦铭老师的数据结构课程很不错,通俗易懂,每周习题还都有点挑战性,这里打算将所有的题进行一下汇 ...

  10. 浙江大学MOOC数据结构-陈越、何钦铭 编程练习题(第一讲)

    浙江大学MOOC数据结构-陈越.何钦铭 编程练习题(第一讲) 编程题目 编程说明 编程环境:Code::Blocks 编程语言:C 注:第一题未在程序平台运行,仅在编程环境运行 第一题代码 #incl ...

最新文章

  1. Flutter开发之MVC设计模式:新建文件与导入文件(八)
  2. SQL 判断两个时间段是否有交叉
  3. python好找工作吗2017-2018年七大工作机会最多的编程语言和技术!
  4. 订单可视化(智能制造、流程再造、企业信息化) 第三篇 订单可视化定义及目标...
  5. React中解决样式丢失问题
  6. 透明(颜色)渐变背景(颜色透明背景),兼容IE8
  7. 当前超级计算机的应用方兴未艾,四川省若尔盖县高三下学期语文模拟卷(五)
  8. python的交互式解释器_python3.4.1解释器python交互式图形编程实例(三)
  9. kotlin 用协程做网络请求_中国电信营业厅: 感受 Kotlin 的 quot;加速度quot;
  10. 用android制作一个记事本app_用扁平化呈现一个天气APP
  11. 金九银十,年轻人跳槽时,尽量不要选择这三类得不偿失的公司
  12. 冒泡排序-C语言版(带图详细)
  13. linu修改open files无效_安卓容器app如何使用 容器app修改机型方法【详解】
  14. Reflector dll反编译工具
  15. 关于计算机的病毒案例分析,实例解析蠕虫病毒的原理 -电脑资料
  16. 专利技术交底书撰写经历
  17. 安卓框架访问QQ文件的路径miui13
  18. QQ邮箱发送验证码(springboot、redis整合)
  19. GIT无法提交到码云。原因可能是所在提交位置不对
  20. iOS app 的开发要准备哪些图标图片?

热门文章

  1. html 渐变背景色,渐变文字颜色
  2. 【AWVS】python调AWVS接口 新建扫描并导出扫描报告 [自定义扫描报告](三)
  3. C/C++学习笔记(2020.11---2021.5)
  4. 关闭或者开启Windows defender防火墙
  5. 主流PC浏览器使用的内核
  6. 使用n2n实现内网访问
  7. 《正确去掉Win7快捷方式小箭头》
  8. 李沐论文精读系列二:Vision Transformer、MAE、Swin-Transformer
  9. 关于笔记本双显卡状态下独立显卡的配置问题
  10. 计算机课搞事情检讨,考试作弊被抓写的检讨书(精选10篇)