特殊的邻接表——立方体邻接表

特殊的邻接表——立方体邻接表:关于链接表的一些特殊情况的考虑

  我们在学习图的时候,都知道常用的保存图的方法有邻接矩阵和邻接表。当图中的边的数量相对于顶点的数量较少是,邻接矩阵中会出现许多0值,即形成了稀疏矩阵。这个时候用邻接表来储存图就可以大大减少储存所需的空间,也即是对矩阵进行了“压缩”。

  邻接表的本质是一种链式储存结构,它保存的是顶点间的邻接关系,也就是只考虑邻接矩阵中的非零元素。很自然会想到通过链表来构建一个邻接表,这是因为各个顶点通过的边的数量绝大多数不相同,用链表的动态分配内存显然更合理,但是还是存在一种特例:所有的顶点上的边的数量都相同。比如立方体,它有八个顶点,但是每个顶点都有且只有与其邻接的三个顶点,在这种各个顶点邻接顶点的数量相同的情况下,就没有必要用链表来储存,用长度固定的数组显然更方便,我称之为立方体邻接表(Cubic Adjacency List,CAL)。

  CAL的定义和邻接表类似,只是各个顶点邻接的顶点数量相同,关于邻接表……大家可以复习以下数据结构课程中的定义。

  下面直接以一个问题来阐述立方体邻接矩阵的结构定义和实际运用。

  问题描述:

    如图所示:

在正方体ABCD-A1B1C1D1  的A点处有一只青蛙(蚂蚁,虫子……什么都行)要跳到C1  点,它每次只能条一步(也就是一条边),当跳满五次或者已经到达目标点时就停止跳动。

(1)求青蛙在5次以内跳到目的点的路线有多少条?

(2)求青蛙所有可能的跳跃方式?

先给出答案,根据排列组合的知识,第一问应该是3X2X1=6条,第二问应该是(33 -6)X3X3+6=195种。下面给出这一题用CAL的源码:

 1 /*Question: there is a frog standing in
 2   A piont in cube ABCD-A1B1C1D1,it must
 3   jump from one place to another within
 4   5 jumps,how many ways does it have?
 5 */
 6 #include <stdio.h>
 7
 8 typedef enum {A,B,C,D,A1,B1,C1,D1} vertex; //定义顶点信息的枚举类型
 9
10 const vertex cube[8][3]=                   /*cube[0]={B,A1,D}表示和A点邻接的是B,A1,D点以此类推,这样就构建了一个正方体*/
11 {
12     {B,A1,D},{A,C,B1},{B,C1,D},{A,C,D1},
13     {A,D1,B1},{A1,C1,B},{D1,B1,C},{A1,D,C1}
14 }; /* using an adjacency list to store graph*/
15
16 long iCount=0;/* 记录所有可以到达C1点的路线的数量*/
17 long iTotal=0;/*记录在5次以内到达的路线数(第一问答案)*/
18 long iSum=0;/*记录所有的路线数(第二问答案)*/
19
20 void Output(vertex path[],long count,int n);//函数原型,输出路径
21 //output function
22
23 int Traverse(int n, vertex p,vertex path[]);//函数原型,遍历邻接表
24 //core func to traverse graph by recusion
25
26 int main(void)
27 {
28     vertex path[5]={A}; //at most 5
29     vertex p=A;//起点在A点
30     Traverse(0,p,path); //calling,遍历
31     printf("All the number of existing paths : %ld \n",iCount);
32     printf("number of thatc an complete the path within five steps :%ld\n",iSum);
33     printf("All possible paths :%ld\n",iTotal);
34     return 0;
35 }
36
37 void Output(vertex path[],long count,int n)//打印信息
38 {
39     int i;
40     printf("Path %ld :",count);
41     for (i=0;i<=n;++i)
42     {
43         switch (path[i])
44         {
45             case A : printf("A-->"); break;
46             case B : printf("B-->");break;
47             case C : printf("C-->");break;
48             case D : printf("D-->");break;
49             case A1 : printf("A1-->");break;
50             case B1 : printf("B1-->");break;
51             case C1 : printf("C1\n");break;
52             case D1 : printf("D1-->");break;
53         }
54     }
55 }
56
57 int Traverse(int n,vertex p,vertex path[])
58 {
59     int i;
60     path[n]=p;
61     if (n==5) //已经跳满五次
62     {
63         ++iTotal; //第三问数量加一
64         if (p==C1)    //已经到C1点
65         {
66             Output(path,++iCount,n);    //iCount,可以到达的路线数量+1,
67             return 1;
68         }
69         else
70             return 0;
71     }
72     if (p==C1) //五步以内到达C1点
73     {
74         ++iTotal;
75         Output(path,++iCount,n);    //输出
76         if (n<5)
77             ++iSum;
78         return 1;
79     }
80     for (i=0;i<3;++i) //没有到,从与某个顶点相邻接的三个点开始进行尝试
81     {
82         Traverse(n+1,cube[(int)p][i],path);//递归调用,遍历邻接表,其中(int)p指的是A~D1点(C语言中枚举类型是整形且默认从0开始)
83     }
84     return 0;
85 }

编译并运行程序后可以发现与数学计算结果吻合(废话!)。由此,我们就成功的用邻接矩阵这种二维的形式保存了三维的立方体。

CAL的用途还有很多,尤其适合解决空间立体图形的问题。但是不管怎样变化,还是那几个常见的算法就可以实现的,简单就是美嘛!



特殊的邻接表——立方体邻接表

时间: 2024-10-18 00:49:13

特殊的邻接表——立方体邻接表的相关文章

mybatis3动态创建表,判断表是否存在,删除表

1.mybatis3动态创建表,判断表是否存在,删除表 mapper配置文件: <span style="font-size:18px;"><?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/

hive join 优化 --小表join大表

1.小.大表 join 在小表和大表进行join时,将小表放在前边,效率会高,hive会将小表进行缓存. 2.mapjoin 使用mapjoin将小表放入内存,在map端和大表逐一匹配,从而省去reduce. 例子: select /*+MAPJOIN(b)*/ a.a1,a.a2,b.b2 from tablea a JOIN tableb b ON a.a1=b.b1 在0.7版本后,也可以用配置来自动优化 set hive.auto.convert.join=true;

hive表与外部表的区别

相信很多用户都用过关系型数据库,我们可以在关系型数据库里面创建表(create table),这里要讨论的表和关系型数据库中的表在概念上很类似.我们可以用下面的语句在Hive里面创建一个表: hive> create table wyp(id int, > name string, > age int, > tele string) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY '\t' > STORED AS TEX

触发器中的inserted表和deleted表

触发器语句中使用了两种特殊的表:deleted 表和 inserted 表.Microsoft? SQL Server 2000 自动创建和管理这些表.可以使用这两个临时的驻留内存的表测试某些数据修改的效果及设置触发器操作的条件:然而,不能直接对表中的数据进行更改. inserted和deleted表主要用于触发器中: ·扩展表间引用完整性 ·在以视图为基础的基表中插入或更新数据 ·检查错误并基于错误采取行动 找到数据修改前后表状态的差异,并基于此差异采取行动. Deleted表用于存储DELE

父表、子表 主外键关系

ORACLE官方文档介绍: Concurrency Control, Indexes, and Foreign Keys You almost always index foreign keys. The only exception is when the matching unique or primary key is never updated or deleted.(你总是需要对 外键添加索引! 唯一的例外就是:匹配的主键列 或是 唯一列 从不进行更新操作或者 删除操作) Oracle

MySQL复制表结构,表数据。

1.复制表结构及数据到新表CREATE TABLE 新表 SELECT * FROM 旧表 这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete from newtable;来删除. 不过这种方法的一个最不好的地方就是新表中没有了旧表的primary key.Extra(auto_increment)等属性.需要自己用"alter"添加,而且容易搞错. 2.只复制表结构到新表 CREATE TABLE 新表 SELECT * FROM 旧表 WHERE 1=2

小甲鱼PE详解之输入表(导入表)详解(PE详解07)

捷径并不是把弯路改直了,而是帮你把岔道堵上! 走得弯路跟成长的速度是成正比的!不要害怕走上弯路,弯路会让你懂得更多,最终还是会在终点交汇! 岔路会将你引入万劫不复的深渊,并越走越深…… 在开始讲解输入表(导入表)概念之前,请允许小甲鱼童鞋用简短的几句话来总结之前我们学过的内容,并做进一步的思想综合提升,注意咯! 首先,我们知道PE 文件中的数据被载入内存后根据不同页面属性被划分成很多区块(节),并有区块表(节表)的数据来描述这些区块.这里我们需要注意的问题是:一个区块中的数据仅仅只是由于属性相同

数据结构Java实现02----线性表与顺序表

[正文] 本节内容: 线性结构 线性表抽象数据类型 顺序表 顺序表应用 一.线性结构: 如果一个数据元素序列满足: (1)除第一个和最后一个数据元素外,每个数据元素只有一个前驱数据元素和一个后继数据元素: (2)第一个数据元素没有前驱数据元素: (3)最后一个数据元素没有后继数据元素. 则称这样的数据结构为线性结构. 二.线性表抽象数据类型: 1.线性表抽象数据类型的概念: 线性表抽象数据类型主要包括两个方面:既数据集合和该数据集合上的操作集合. 数据集合: 可以表示为a0,a1,a2,...a

求LR(0)文法的规范族集和ACTION表、GOTO表的构造算法

原理 数据结构 1 // GO 2 private static Map<Map<Integer,String>,Integer> GO 3 = new HashMap<Map<Integer,String>,Integer>(); 4 5 // 规范族集 C 6 private static Map<Integer,Map<String,List<String>>> C 7 = new HashMap<Intege