-
2018-08-20 11:21:43
创建一个交换链
本节的代码是
05-init_swapchain.cpp
本节描述如何创建交换链,它是最终显示给用户的图像缓冲区列表。这是建立呈现所需的所有缓冲区所需的第一个步骤之一。
这是一个关于交换链的视图,它与系统的其他部分有关。其中一些部分很常见,剩下的部分将在本节中学习。
Vulkan和窗口系统
与其他图形API一样,Vulkan将窗口系统方面与核心图形API分离开来。
在Vulkan中,窗口系统的详细信息通过WSI(窗口系统集成)扩展公开。
您可以在使用WSI内容的Vulkan规范文档中找到这些扩展的文档。Vulkan 规范LunarG LunarXchange website 和 Khronos Vulkan Registry 。WSI扩展包含对各种平台的支持。扩展被激活为一个特定的平台,通过定义:
VK_USE_PLATFORM_ANDROID_KHR
- AndroidVK_USE_PLATFORM_MIR_KHR
- MirVK_USE_PLATFORM_WAYLAND_KHR
- WaylandVK_USE_PLATFORM_WIN32_KHR
- Microsoft WindowsVK_USE_PLATFORM_XCB_KHR
- X Window System, using the XCB libraryVK_USE_PLATFORM_XLIB_KHR
- X Window System, using the Xlib library
该名称的“KHR”部分表明该符号是在Khronos扩展中定义的。
Surface 抽象
Vulkan使用
VkSurfaceKHR
对象来抽象本机平台的Surface 或窗口。这个符号定义为VK KHR表面扩展的一部分。WSI扩展中的各种函数被用来创建、操作和销毁这些Surface 对象。回顾实例和设备扩展
由于您在本教程前几节中推迟了使用扩展,现在是重新回顾它们的时候了,这样您就可以激活WSI扩展,您需要使用它来与窗口系统进行交互。
实例扩展
为了使用WSI扩展,您需要激活通用的surface 扩展。在示例中找到
init_instance_extension_names()
函数中的代码,该函数将init_instance_extension_names()
添加到加载的实例扩展列表中。info.instance_extension_names.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
还要注意的是,这个函数决定了特定于平台的扩展,这取决于所构建代码的平台。
例如,如果为Windows构建的话,该函数会将VK_KHR_WIN32_SURFACE_EXTENSION_NAME
添加到加载的实例扩展列表中。info.instance_extension_names.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
当实例被创建时,在
init_instance()
函数中加载这些扩展。设备扩展
交换链是一个GPU渲染图像缓冲区列表,并将其呈现给显示硬件,以便扫描输出到显示器。
由于GPU硬件是为这些图像编写的,所以需要一个设备级的扩展来处理交换链。
因此,样例代码将VK_KHR_SWAPCHAIN_EXTENSION_NAME
的设备扩展添加到设备扩展列表中,以便加载init_device_extension_names()
。info.device_extension_names.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
这个扩展在本节稍后将使用,用以创建交换链。
简要概括:
- 本示例使用
init_instance_extension_names()
函数来加载一般的surface扩展和特定于平台的surface扩展作为实例扩展。 - 该示例使用
init_device_extension_names()
函数来加载交换链扩展作为设备扩展。
通过访问LunarG LunarXchange website.,您可以了解更多关于实例和设备扩展的信息
队列家族 和“呈现”
“呈现”操作包括将一个交换链的图像放到物理显示器上,这样就可以查看它了。当应用程序想要将图像呈现给显示器时,它会使用
vkQueuePresentKHR()
函数将当前请求放到GPU的队列中。因此,这个函数引用的队列必须能够支持呈现请求,或者图形和呈现请求。示例如下:// Iterate over each queue to learn whether it supports presenting: VkBool32 *pSupportsPresent = (VkBool32 *)malloc(info.queue_family_count * sizeof(VkBool32)); for (uint32_t i = 0; i < info.queue_family_count; i++) { vkGetPhysicalDeviceSurfaceSupportKHR(info.gpus[0], i, info.surface, &pSupportsPresent[i]); } // Search for a graphics and a present queue in the array of queue // families, try to find one that supports both info.graphics_queue_family_index = UINT32_MAX; info.present_queue_family_index = UINT32_MAX; for (uint32_t i = 0; i < info.queue_family_count; ++i) { if ((info.queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if (info.graphics_queue_family_index == UINT32_MAX) info.graphics_queue_family_index = i; if (pSupportsPresent[i] == VK_TRUE) { info.graphics_queue_family_index = i; info.present_queue_family_index = i; break; } } } if (info.present_queue_family_index == UINT32_MAX) { // If didn't find a queue that supports both graphics and present, then // find a separate present queue. for (size_t i = 0; i < info.queue_family_count; ++i) if (pSupportsPresent[i] == VK_TRUE) { info.present_queue_family_index = i; break; } } free(pSupportsPresent);
这段代码重新使用了之前获得的
info.queue_family_count
,因为vkGetPhysicalDeviceSurfaceSupportKHR()
为每个队列家族返回一个flag。
然后搜索一个同时支持呈现和图形的队列家族。如果没有队列家族能同时满足呈现和图形,程序会先记住支持图形的队列家族,然后再去搜索支持呈现的队列家族。
当graphics_queue_family_index
和present_queue_family_index
都被这段代码设置时,示例的后面必须使用来自graphics_queue_family_index
的队列用于图形指令,以及来自present_queue_family_index
的队列用于呈现。是的,这有点冗余,之前在“设备”章节中只进行了搜索一个支持图形的队列家族,这只是为了便于说明。一个真正的应用程序可以以不同的顺序执行这些步骤,以避免重复。
如果没有这样的队列家族,示例程序会直接退出。
交换链创建信息
本节其余部分的大部分工作都是为了填充这个create info结构,用于创建交换链:
typedef struct VkSwapchainCreateInfoKHR { VkStructureType sType; const void* pNext; VkSwapchainCreateFlagsKHR flags; VkSurfaceKHR surface; uint32_t minImageCount; VkFormat imageFormat; VkColorSpaceKHR imageColorSpace; VkExtent2D imageExtent; uint32_t imageArrayLayers; VkImageUsageFlags imageUsage; VkSharingMode imageSharingMode; uint32_t queueFamilyIndexCount; const uint32_t* pQueueFamilyIndices; VkSurfaceTransformFlagBitsKHR preTransform; VkCompositeAlphaFlagBitsKHR compositeAlpha; VkPresentModeKHR presentMode; VkBool32 clipped; VkSwapchainKHR oldSwapchain; } VkSwapchainCreateInfoKHR;
创建一个表面(Surface)
随着WSI扩展在实例和设备中加载,您现在可以创建一个
VkSurface
,这样您就可以继续进行构建交换链了。您再次需要使用特定于平台的代码,出现在05-init_swapchain.cpp
的顶部:#ifdef _WIN32 VkWin32SurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.hinstance = info.connection; createInfo.hwnd = info.window; res = vkCreateWin32SurfaceKHR(info.inst, &createInfo, NULL, &info.surface); #endif
info.connection
和info.window
的值是在init_connection()
和init_window()
函数中包含的更特定于平台的代码中设置的,您也可以在示例代码中找到它们。请注意,
init_connection()
和init_window()
函数也负责连接到显示器的特定于平台的操作,并创造实际的窗口。您刚刚用vkCreateWin32SurfaceKHR()
函数创建的VkSurfaceKHR
是由Vulkan用于平台窗口对象的句柄来表示的。然后将生成的表面添加到交换链的create info结构:
VkSwapchainCreateInfoKHR swapchain_ci = {}; swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_ci.pNext = NULL; swapchain_ci.surface = info.surface;
设备表面格式(Device Surface Formats)
您还需要在创建交换链时指定表面的格式。在这种情况下,“格式”指的是
VkFormat
枚举所描述的像素格式,
VK_FORMAT_B8G8R8A8_UNORM
是设备表面格式的一个常见值。示例中的下一段代码将获得
VkSurfaceFormatKHR
结构的列表,其中包含由display支持的VkFormat
格式,以及其他信息。因为这些示例并不关心
显示图像和表面使用的格式,所以示例只是选择了第一个可用的格式,如果没有指定的话,就会返回到任意的、但常见的格式。看一看示例中的代码,它最终在create info结构中设置了格式:
swapchain_ci.imageFormat = info.format;
表面能力(Surface Capabilities)
为了继续填充 create info 结构, 示例调用
vkGetPhysicalDeviceSurfaceCapabilitiesKHR()
和vkGetPhysicalDeviceSurfacePresentModesKHR()
来获得必要的信息。 然后,它可以填充以下字段:uint32_t desiredNumberOfSwapChainImages = surfCapabilities.minImageCount; swapchain_ci.minImageCount = desiredNumberOfSwapChainImages; swapchain_ci.imageExtent.width = swapChainExtent.width; swapchain_ci.imageExtent.height = swapChainExtent.height; swapchain_ci.preTransform = preTransform; swapchain_ci.presentMode = swapchainPresentMode;
您应该将
minImageCount
成员设置为代表应用程序使用的缓冲策略的值,例如双缓冲或三重缓冲。这个示例查询一个交换链中可以使用的最少数量的图像,这些图像使用的是vkGetPhysicalDeviceSurfaceCapabilitiesKHR()
函数,将结果存储在surfCapabilities
中。要求这个最小数量的图像可以确保我们可以获得一个可呈现的图像,只要我们在试图获得另一个图像之前就展示它。这表示一个双缓冲配置,因为您将让一个图像进行渲染,而另一个图像正在呈现。如果你想要三次缓冲,那么你会要求一个更多的图像,然后在你展示它们之前,你可以获得两个缓冲。用于图形和当前的不同队列家族
您在队列家族中确定了图形和呈现队列。如果它们是不同的,您需要做一些额外的工作,以允许在队列家族之间共享图像。
swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_ci.queueFamilyIndexCount = 0; swapchain_ci.pQueueFamilyIndices = NULL; uint32_t queueFamilyIndices[2] = { (uint32_t)info.graphics_queue_family_index, (uint32_t)info.present_queue_family_index}; if (info.graphics_queue_family_index != info.present_queue_family_index) { // If the graphics and present queues are from different queue families, // we either have to explicitly transfer ownership of images between the // queues, or we have to create the swapchain with imageSharingMode // as VK_SHARING_MODE_CONCURRENT swapchain_ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchain_ci.queueFamilyIndexCount = 2; swapchain_ci.pQueueFamilyIndices = queueFamilyIndices; }
上面的字段提供了创建交换链所需的更多基本信息。您可以在示例中检查其余的代码,以了解如何获得这些信息,以及如何填写create info结构的其余部分。
创建交换链
当交换链的 create info 结构填充完成,你现在就可以创建交换链了:
res = vkCreateSwapchainKHR(info.device, &swapchain_ci, NULL, &info.swap_chain);
这个调用创建了组成交换链的一组图像。在某种程度上,你需要对单个图像进行处理,这样你就可以告诉GPU哪些图像用于渲染。
vkCreateSwapchainKHR()
函数创建图像本身,因此保持了对句柄的跟踪。
样例通过使用我们熟悉的查询模式来获得图像句柄的个数,通过调用vkGetSwapchainImagesKHR(info.device, info.swap_chain, &info.swapchainImageCount, NULL);
然后再次调用这个函数来获取一张图像句柄的列表,并将它们存储在
info.buffer
中。现在你有了一个目标图像句柄的列表。创建图像视图(Create Image Views)
您需要告诉Vulkan,通过创建图像视图,您打算如何使用这些交换链图像。“视图”本质上是附加到一个资源的附加信息,该信息了如何使用该资源。
属于图像的内存区域可以以多种方式排列,这取决于图像的预期用途。例如,图像可以是1D、2D或3D。或者可以有一系列的图像,等等。描述图像的格式(例如,
VK_FORMAT_R8G8B8A8_UNORM
)、组件的顺序和层信息也是很有用的。所有这些信息都是包含在VkImageView
中的图像元数据。创建图像视图非常简单。在
05-init_swapchain.cpp
中找到VkImageViewCreateInfo
结构。并看到它被填充了你对2D framebuffer所期望的值。注意图像句柄本身存储在图像视图中。然后,您可以通过在
info
数据结构中存储图像视图句柄来完成交换链的创建,以便以后使用。© Copyright 2016 LunarG, Inc
更多相关内容 -
图的创建 --- 十字链表法.zip
2020-08-24 18:19:49压缩包中为 十字链表法创建图的 C 文件源文件,及对应的PPT 博客《【经典算法实现 30】图的创建 --- 十字链表法》 链接:https://blog.csdn.net/Ciellee/article/details/108199838 -
【一个大坑,持续更新】番外之区块链之创建泰安链账户、泰安链项目和生成公钥私钥
2022-03-28 15:24:42文件转换三、创建一个泰安链项目总结 前言 提示:这里可以添加本文要记录的大概内容: 最开始了解BSN是因为BSN的开发者大赛,如果你想尝试一下开发或学习区块链的相关知识,我认为是一个很好的入门平台。 来看一下...提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容:
最开始了解BSN是因为BSN的开发者大赛,如果你想尝试一下开发或学习区块链的相关知识,我认为是一个很好的入门平台。
来看一下它的简介:区块链服务网络BSN(“服务网络”或者“BSN”)是为开发者提供了一站式的区块链开发、部署和运行环境服务,整合了各大云服务商、框架商以及多个门户方的资源。因为涉及到编程开发、配置资源、部署应用、网关调用、以及密钥证书等多个方面,因此BSN官方门户(bsnbase.com)为开发者准备了帮助手册(http://kb.bsnbase.com/webdoc/view/Pub4028813e705bf9760170a92185bd1277.html),帮助开发者顺利掌握BSN的使用技巧,从而能够将BSN作为区块链开发和部署的首选工具。
更多的内容你可以自己去他的网站上探索~,这里使用到的是BSN中提供的开放联盟链中的泰安链。
开放联盟链是用于部署和运行各类区块链应用的一站式区块链服务运行环境。与传统联盟链服务相比,开放联盟链的应用共享记账节点资源,不同应用的智能合约可以相互可见及调用,共享使用区块链数据账本;链外业务系统可以通过节点网关简单、快速接入区块链网络进行交易处理。
目前BSN开放联盟链已推出文昌链(基于IRITA)、泰安链(基于FISCO BCOS)、武汉链(基于Ethereum)、唐山链(基于DBChain)、广元链(基于Everscale)和中移链(基于EOS),BSN后续将持续集成更多的底层框架,欢迎大家使用并提出宝贵的意见和建议。目前除了广元链支持密钥托管(这个模式适合不想写太多代码的开发者)之外,所有的其他开放联盟链都只能采用上传公外和上传账户地址的方式创建链账户。而广元链账户创建之前要注意提前创建好广元链的项目和部署智能合约。
一、创建一个泰安链账户
点击图片右边的创建账户
取一个名字然后选择“上传公钥”模式,目前bsn已经取消了泰安链的密钥托管模式(没有密钥托管模式就不能线上部署智能合约)然后进入下一步,生成自己的公钥私钥。不用选择在线生成。
二、生成公钥私钥
1.下载并安装openssl
下载安装openssl并配置环境变量。https://www.openssl.org/source/
找一个安装教程,到官网中下载最新版的openssl2.生成公钥
打开命令行,终端输入 openssl 进入open ssl命令行(如果这一步都不行请检查有没有配置环境变量或环境变量配置是否正确)
输入命令:
官方文档中提供的命令是:ecparam -name prime256v1 -genkey -out key.pem。
但是泰安链的框架是FISCO-secp256k1,其他的算法也要使用对应的加密算法,因此这里要改动一下语句,使用secp256k1 加密算法,注意算法不能错,错了就会导致测试失败无法成功创建。
ecparam -name secp256k1 -genkey -out key.pem
因为没有指定目录,所以我生成的文件保存在了C:\Users\Lenovo目录下。
3.生成私钥
输入命令 ec -in key.pem -pubout -out pub.pem 用key.pem文件中的私钥生成一个公钥文件pub.pem
ec -in key.pem -pubout -out pub.pem
执行结果:
read EC key
writing EC key4.生成签名文件
先在已经生成的公钥私钥文件夹中新建一个文件data.txt,里面随便写上字符串(helloworld可在是程序员DNA里的)
输入命令 dgst -sha256 -sign key.pem -out signature.bin data.txt 用key.pem文件中的私钥对data.txt文件进行签名生成签名文件signature.bindgst -sha256 -sign key.pem -out signature.bin data.txt
如果你报错了,那就赶紧检查一下的data.txt文件存不存在!
5.签名验签
输入命令 dgst -verify pub.pem -sha256 -signature signature.bin data.txt 用pub.pem文件中的公钥对data.txt和signature.bin文件进行签名验签
dgst -verify pub.pem -sha256 -signature signature.bin data.txt
执行结果:
Verified OK6.文件转换
如果显示Verified OK,输入命令 base64 -in signature.bin -out signature64.txt 将签名文件signature.bin转换成base64编码的 signature64.txt文件
base64 -in signature.bin -out signature64.txt
注意,这一步可能报错,我也不知道报错的原因是什么,尝试同样的语句再运行一遍就好了。。。很奇怪
输入命令 pkcs8 -topk8 -inform PEM -in key.pem -outform PEM -nocrypt -out keypkcs8.pem 将key.pem文件中的私钥转为pkcs8格式
pkcs8 -topk8 -inform PEM -in key.pem -outform PEM -nocrypt -out keypkcs8.pem
本地自行保存好keypkcs8.pem文件,并将pub.pem、data.txt 和signature64.txt中的全部内容对应复制到上传公钥模式页面的公钥、测试数据和签名数据文本框中进行验证并提交。
如果测试失败请检查使用的算法是否匹配,以及是否将文件中的全部内容复制到文本框中。
三、创建一个泰安链项目
右侧开放联盟链中选择项目管理,点击右上角创建项目。
输入项目名称和选择框架即可。框架选择后不可以更改。
下载接入参数文件以便后续使用。总结
到目前为止还不是很坑,下一个番外是关于建立你自己的FISCO-BCOS区块链的证书。
-
一起来创建一个无向图吧!
2019-11-26 09:25:40创建图可是遍历的基础呢,虽然写了广度优先遍历()和深度优先遍历(DFS),但是自己对于创建图这一块还是想再来一遍(once again?),基础也是很重要的。 我们都...前言:
创建图可是遍历的基础呢,虽然写了广度优先遍历()和深度优先遍历(DFS),但是自己对于创建图这一块还是想再来一遍(once again?),基础也是很重要的。
我们都知道图的储存结构表示有多种:邻接矩阵、邻接表十字链表、邻接多重表。这里重点交接邻接表(因为自己用的比较多),邻接矩阵也会涉及。其它的两种其实本质都是一样的,可以自己去深入。
来!看一下邻接表相关概念:
邻接表是图的一种链式存储结构。在邻接表中,对图中每个顶点vi建立一个单链表,把与vi相邻接的顶点放在这个链表中。邻接表中每个单链表的第一个节点存放有关顶点的信息,把这一结点看成链表的表头,其余结点存放有关边的信息,这样邻接表遍由两部分组成:表头结点表和边表。- (1)表头节点表:由所有表头结点以顺序结构的形式存储,以便可以随机访问任意顶点的边链表。扁头节点包括数据域和链域两部分。其中数据域用于存储顶点vi的名称或其它有关信息;链域用于指向链表中第一个结点(即与顶点vi邻接的第一个邻接点)。
- (2)边表:由表示图中顶点间关系的2n个边链表组成。边链表中边结点包括邻接点域、数据域和链域三部分。其中,邻接点域指示与顶点vi邻接的点在图中的位置;数据域存储边相关的信息,如权值等;链域指示与顶点vi邻接的下一条边的节点。
一、邻接表创建无向图的代码:
#include <iostream> using namespace std; #define MVNum 100 //最大顶点数 #define OK 1 typedef char VerTexType; //顶点信息 typedef int OtherInfo; //和边相关的信息 //- - - - -图的邻接表存储表示- - - - - typedef struct ArcNode{ //边结点 int adjvex; //该边所指向的顶点的位置 struct ArcNode *nextarc; //指向下一条边的指针 OtherInfo info; //和边相关的信息 }ArcNode; typedef struct VNode{ VerTexType data; //顶点信息 ArcNode *firstarc; //指向第一条依附该顶点的边的指针 }VNode, AdjList[MVNum]; //AdjList表示邻接表类型 typedef struct{ AdjList vertices; //邻接表 int vexnum, arcnum; //图的当前顶点数和边数 }ALGraph; int LocateVex(ALGraph G , VerTexType v){ //确定点v在G中的位置 for(int i = 0; i < G.vexnum; ++i) if(G.vertices[i].data == v) return i; return -1; }//LocateVex int CreateUDG(ALGraph &G){ //采用邻接表表示法,创建无向图G int i , k; cout <<"请输入总顶点数,总边数中间以空格隔开:"; cin >> G.vexnum >> G.arcnum; //输入总顶点数,总边数 cout << endl; cout << "输入点的名称,如 a " <<endl; for(i = 0; i < G.vexnum; ++i){ //输入各点,构造表头结点表 cout << "请输入第" << (i+1) << "个点的名称:"; cin >> G.vertices[i].data; //输入顶点值 G.vertices[i].firstarc=NULL; //初始化表头结点的指针域为NULL }//for cout << endl; cout << "请输入一条边依附的顶点,如 a b" << endl; for(k = 0; k < G.arcnum;++k){ //输入各边,构造邻接表 VerTexType v1 , v2; int i , j; cout << "请输入第" << (k + 1) << "条边依附的顶点:"; cin >> v1 >> v2; //输入一条边依附的两个顶点 i = LocateVex(G, v1); j = LocateVex(G, v2); //确定v1和v2在G中位置,即顶点在G.vertices中的序号 ArcNode *p1=new ArcNode; //生成一个新的边结点*p1 p1->adjvex=j; //邻接点序号为j p1->nextarc= G.vertices[i].firstarc; G.vertices[i].firstarc=p1; //将新结点*p1插入顶点vi的边表头部 ArcNode *p2=new ArcNode; //生成另一个对称的新的边结点*p2 p2->adjvex=i; //邻接点序号为i p2->nextarc= G.vertices[j].firstarc; G.vertices[j].firstarc=p2; //将新结点*p2插入顶点vj的边表头部 }//for return OK; }//CreateUDG int main(){ cout << "************采用邻接表表示法创建无向图**************" << endl << endl; ALGraph G; CreateUDG(G); int i; cout << endl; cout << "*****邻接表表示法创建的无向图*****" << endl; for(i = 0 ; i < G.vexnum ; ++i){ VNode temp = G.vertices[i]; ArcNode *p = temp.firstarc; if(p == NULL){ cout << G.vertices[i].data; cout << endl; } else{ cout << temp.data; while(p){ cout << "->"; cout << p->adjvex; p = p->nextarc; } } cout << endl; } return 0; }//main
给出一个列子:
二、用邻接矩阵创建无向图
#include <iostream> using namespace std; #define MaxInt 32767 //表示极大值,即∞ #define MVNum 100 //最大顶点数 #define OK 1 typedef char VerTexType; //假设顶点的数据类型为字符型 typedef int ArcType; //假设边的权值类型为整型 //- - - - -图的邻接矩阵存储表示- - - - - typedef struct{ VerTexType vexs[MVNum]; //顶点表 ArcType arcs[MVNum][MVNum]; //邻接矩阵 int vexnum,arcnum; //图的当前点数和边数 }AMGraph; int LocateVex(AMGraph G , VerTexType v){ //确定点v在G中的位置 for(int i = 0; i < G.vexnum; ++i) if(G.vexs[i] == v) return i; return -1; }//LocateVex int CreateUDN(AMGraph &G){ //采用邻接矩阵表示法,创建无向网G int i , j , k; cout <<"请输入总顶点数,总边数,以空格隔开:"; cin >> G.vexnum >> G.arcnum; //输入总顶点数,总边数 cout << endl; cout << "输入点的名称,如a" << endl; for(i = 0; i < G.vexnum; ++i){ cout << "请输入第" << (i+1) << "个点的名称:"; cin >> G.vexs[i]; //依次输入点的信息 } cout << endl; for(i = 0; i < G.vexnum; ++i) //初始化邻接矩阵,边的权值均置为极大值MaxInt for(j = 0; j < G.vexnum; ++j) G.arcs[i][j] = MaxInt; cout << "输入边依附的顶点及权值,如 a b 5" << endl; for(k = 0; k < G.arcnum;++k){ //构造邻接矩阵 VerTexType v1 , v2; ArcType w; cout << "请输入第" << (k + 1) << "条边依附的顶点及权值:"; cin >> v1 >> v2 >> w; //输入一条边依附的顶点及权值 i = LocateVex(G, v1); j = LocateVex(G, v2); //确定v1和v2在G中的位置,即顶点数组的下标 G.arcs[i][j] = w; //边<v1, v2>的权值置为w G.arcs[j][i] = G.arcs[i][j]; //置<v1, v2>的对称边<v2, v1>的权值为w }//for return OK; }//CreateUDN int main(){ cout << "采用邻接矩阵表示法创建无向网**************" << endl << endl; AMGraph G; int i , j; CreateUDN(G); cout <<endl; cout << "*****邻接矩阵表示法创建的无向网*****" << endl; for(i = 0 ; i < G.vexnum ; ++i){ for(j = 0; j < G.vexnum; ++j){ if(j != G.vexnum - 1){ if(G.arcs[i][j] != MaxInt) cout << G.arcs[i][j] << "\t"; else cout << "∞" << "\t"; } else{ if(G.arcs[i][j] != MaxInt) cout << G.arcs[i][j] <<endl; else cout << "∞" <<endl; } } }//for cout <<endl; return 0; }//main
后记:
只有掌握基础的存储结构,才可以更好的往下走。冲鸭!如有更好的结构,评论哦!
-
图片生成链接最简单的方法
2020-12-14 10:29:42有时候我们需要将几张图片生成链接或者二维码,...我们的目的非常简单,就是希望别人扫一扫或者直接点击就能看到一连串的图片,而不是像某些图床工具把图片生成一个又一个的链接。 首先我们打个腹稿,在心中想一想如何有时候我们需要将几张图片生成链接或者二维码,方便进行各种场景的展示和分享。因为链接是可以在各种设备和系统打开的。比如微信好友或朋友圈发一些类似H5页面的链接,类似于公众号一样自带缩略图和简介的小方格.如果自己去申请公众号来设置,会异常复杂.我们知道公众号虽然门槛低,但是从来没有接触过的人会在使用上有困难。但是有一些简单好用的方法也一样可以达到这个效果。
我们的目的非常简单,就是希望别人扫一扫或者直接点击就能看到一连串的图片,而不是像某些图床工具把图片生成一个又一个的链接。
首先我们打个腹稿,在心中想一想如何设置自己的微信分享小方块。比如:显示什么图片,什么标题,什么简介这三点。因为您上传的第一张图片将作为微信缩略图展示的小方格。 我们进入图床制作器进行图片的上传和阅读次数的设置比如麦瓜图床。如果对展示顺序有要求的,可以将图片按字母或者数字的排列顺序进行图片的命名。然后我们就可以将图片进行上传了。 (上传的方式非常简单易用,直接把图片拖拽,或者选择图片进行上传,手机上操作也是一样的简便,可以一次性选择多张图片进行上传) 上传之后,会提示是否上传成功。待上传成功之后,我们再进行下一步的设置,图片链接打开的次数和每次的阅读时间。如果想设置阅后即焚的效果,可以设置打开次数1,阅读时间60秒,这样别人在打开一次之后就无法打开第二次了。
在生成链接之后就可以分享出去了!有两种方式可以展示图片,一种是滑动的轮播图片,还有一种是非常适合长图的自适应轮播图。 而且我们还可以根据追踪链接来进行阅读记录的查看! 链接可以很快的生成为二维码,在该工具的同一页面下,输入生成的图片链接,会自动转成一个二维码,我们既可以用链接去直接分享,又可以把二维码贴在某个地方,供大家扫一扫进行查阅
在图片分享出去之后,我们依然可以对该链接和二维码进行追踪,比如该链接打开了几次?在哪个城市打开的?打开的设备都是什么?是不是用微信打开还是用电脑打开的等待。
能追踪就意味着能控制:我们可以在将图片分享出去之后,对图片进行不换链接换图片的方式进行更改。 -
蚂蚁区块链第19课 联盟链创建及管理
2020-02-01 19:43:21联盟是一个虚拟组织,由多个机构组成。联盟机构可以: 共享联盟区块链 创建区块链应用,并共享给联盟内的其他机构 创建联盟 登录控制台,点击 产品与服务 > 区块链 >... -
在github上快速创建文件夹以及生成链接的详尽步骤
2017-11-28 12:06:39在github中快速创建文件夹以及生成文件链接,简单明了,一步到位,傻瓜式的创建。 -
创建一个简单的单链表
2020-05-15 23:33:04数据结构创建单链表的基本操作 一、构造单链表的结构体 typedef struct LNode { ElemType data;//结点的数据域 struct LNode*next;//结点的指针域 }LNode,*LinkList;... L)//创建一个空的单链表 { L = new LNode -
创建一个完整的SpringBoot项目(含详细pom.xml链接)
2019-07-03 18:29:40如何创建一个完整的SpringBoot项目 Spring Boot项目可以直接创建然后配置,也可以通过创建Maven项目的方法创建SpringBoot项目 本文主要讲述的是创建一个Maven项目,并将其转为一个SpringBoot项目 1、新建一个... -
使用Numpy创建纯色图片
2019-06-03 00:20:40那就意味着可以通过numpy来创建一个图片 如果电脑上没有numpy的话需要先装一下 pip install numpy 可以通过numpy的zeros来创建一个空数组 import cv2 as cv import numpy as np def create_image(): ... -
Spring是怎么创建一个Bean的?
2020-02-12 13:31:38需要看源码直接看AbstractAutowireCapableBeanFactory#doCreateBean 直接看下流程图: 流程: 创建实例:createBeanInstance(beanName, mbd, args)创建一个带有bean实例的BeanWrapper 收集注解:通过... -
创建一个成功的NFT,总共分几步?
2022-04-11 11:35:17看到消息说某某人通过 NFT 赚得盆满钵满的时候,你的脑海会不会闪过一个念头——“不如我也来创个项目吧,或许下一个通过区块链致富的就是我呢?” 创建 NFT 的第一步,就是...那么创建一个成功的NFT,总共分几步?. -
一:创建第一个SpringBoot项目
2019-01-07 17:04:14spring boot 它的设计目的就是为例简化开发,开启了各种自动装配,你不想写各种配置文件,引入相关的依赖就能迅速搭建起一个web工程。它采用的是建立生产就绪的应用程序观点,优先于配置的惯例,慢慢的,你会爱上它... -
linux系统指令学习(创建目录,在目录下创建一个*.txt,*.txt输入内容,把*.txt文件拷贝到*目录下,把*...
2019-04-14 18:36:321.创建一个目录/dzqc 提示: windows下的路径样式为c: \dzqc\ test,而linux下的路径样式为 /dzqc/test 因此/dzqc就可以看做是c:\dzqc,不同的是 windows系统下还有D,E等盘, linux下就只有/为所有目录的顶点。 英文 ... -
安装anaconda并创建一个tensorflow环境的详细教程
2020-11-27 20:45:56安装Anaconda并创建tensorflow环境超级详细教程 二话不说先上资源链接: 百度云盘链接地址: https://pan.baidu.com/s/1Me9cLJ5LRhxuDmXoLkOIjA 提取码:yq23 (此版本为本人将要演示的安装版本) 如果感觉此版本不太... -
JavaScript对象原型链原理解析
2020-11-21 23:06:07一个js对象,除了自己设置的属性外,还会自动生成proto、class、extensible属性,其中,proto属性指向对象的原型。 对象的属性也有writable、enumerable、configurable、value和get/set的配置方法。 对象的创建方式... -
十字链表创建的实验报告
2009-03-14 21:35:57在这种结构中,稀疏矩阵中的每一个非零元素对应一个结点,每个结点有5个域组成,其中3个数据域分别存放结点的行、列及元素值,2个指针域存放向下的指针(down)与向右的指针(right)如图2.20所示。由于这种结点链接成... -
如:汽车软件(OSEK和AUTOSAR)及其工具链
2021-02-03 09:50:36如下图所示,它是一个基于AUTOSAR的虚拟集群,可以在Windows和Linux上进行模拟。 关键点 1. BSW 1.1集成ArcCore AUTOSAR 3.1 BSW 通讯:Can(CanFD)CanIf PduR Com SoAd J1939Tp 诊断:CanTp Dcm DoIP Dem 系统... -
利用Python+opencv创建图像、读取图像文件、获得图像属性等操作
2019-01-14 21:18:07看到一个图片,不要将其当作图片,在你眼里,其实就是一个一个小格子,每个格子都有一个数值,也就是一个矩阵,格子里的数值其实就是灰度值,对于多通道的彩色图片来说,其实就相当于多个灰度图的叠加,只是说叠加的... -
linux中ln(link)命令创建链接以及链接的删除和更新
2018-05-27 16:37:14ln(即link) 的功能是为某一个文件在另外一个位置建立一个同步的链接。有两种链接方式,一种是硬链接(hard link),另一种是符号链接(symbolic link),又称软链接。硬链接和原有文件是存储在同一物理地址的两个... -
DeFi科普 | 新兴公链之争拉响,埋伏下一个「公链之王」
2021-09-24 15:38:15有人说 Crypto 领域的投资发展史,就是一部 ETH 扩容史。 一直以来,不管是在比特币网络或以太坊网络上,与传统网络相比,「速度」一直以来都是待解决的问题,Gas fee昂贵,用户为了扩大收益率,让资产在不同链... -
创建一个最简单的链表,插入和删除
2018-09-04 21:38:43创建一个链表 一、头插法创建链表: #include <stdio.h> struct list { int num; struct list *next; }; typedef struct list list_single; list_single *creat_list_tail(int n)//尾插法... -
Java设计模式实现一个责任链设计模式,从数据结构可以理解为单向链表
2021-05-18 09:31:28定义一个抽象类,具体的过滤需要实现这个抽象类中的doFilter抽象方法 public abstract class TitleFilterChain { protected static Logger logger = LoggerFactory.getLogger... -
RobotStudio仿真—Smart组件创建动态输送链
2017-06-20 19:42:12一、Smart组件 创建受信号与属性控制的动作组件。 不同于事件管理器的是,它适用于中大型工作站应用中,显示动态工作流程,更直观。 二、码垛工作站 产品从输送链一端产生,然后沿着输送链运动... -
dubbo调用链/过滤器链的创建分析
2017-02-01 12:15:48这个功能的实现是通过Dubbo内置的Filter或用户自定义的Filter来创建调用链完成。当发起方法调用时,会执行调用链各个结点的方法,以完成一些处理工作。 调用链/过滤器链的创建分析 调用链的构 -
windows 系统创建文件链接 mklink
2018-06-16 13:39:09mklink [选项] 链接文件 目标文件链接文件:即我们要创建的链接到某个目录或文件的“类似快捷方式”的文件目标文件:要链接到的目录或文件常用选项: /D:创建目录链接(若无则是创建文件链接) 其他两个选项用得不... -
sqlserver中创建链接服务器图解教程
2017-12-01 14:54:451.展开服务器对象-->链接服务器-->右击"新建链接服务器" 注意:必须以数据库管理员身份登录(通常也就是sa帐号)后,才...现在测试一下,用帐号user本地登录SqlServer,新建一个查询,输入Select * From [链接服 -
(三)以太坊——在以太坊私有链上部署第一个智能合约
2021-08-13 10:27:55一、编写示例智能合约 智能合约: 它是一段代码和数据的集合,可以部署以太坊网络上运行。类似于Java程序,Java程序通过Java虚拟机(JVM)将代码解释字节进行执行,以太坊的智能合约通过以太坊虚拟机(EVM)解释成... -
JavaScript对象原型链原理详解
2021-01-21 11:09:21一个js对象,除了自己设置的属性外,还会自动生成proto、class、extensible属性,其中,proto属性指向对象的原型。 对象的属性也有writable、enumerable、configurable、value和get/set的配置方法。 对象的创建方式...