原文:
经典算法题每日演练——第二十题 三元组
我们知道矩阵是一个非常强大的数据结构,在动态规划以及各种图论算法上都有广泛的应用,当然矩阵有着不足的地方就是空间和时间
复杂度都维持在N2上,比如1w个数字建立一个矩阵,在内存中会占用1w*1w=1亿的类型空间,这时就会遇到outofmemory。。。那么面
临的一个问题就是如何来压缩矩阵,当然压缩的方式有很多种,这里就介绍一个顺序表的压缩方式:三元组。
一:三元组
有时候我们的矩阵中只有零星的一些非零元素,其余的都是零元素,那么我们称之为稀疏矩阵,当然没有绝对的说有多少个零元素才算稀疏。
针对上面的这个无规律的存放非零元素,三元组提出了一种方法,就是仅仅记录矩阵中的非零元素以及它的行,列以及值N(x,y,v)构成的一个三元
组,标识一个稀疏矩阵的话,还要记录该矩阵的阶数,这样我们就将一个二维的变成了一个一维,极大的压缩的存储空间,这里要注意的就是,三
元组的构建采用“行“是从上到下,“列”也是从左到右的方式构建的顺序表。
1 /// <summary> 2 /// 三元组 3 /// </summary> 4 public class Unit 5 { 6 public int x; 7 public int y; 8 public int element; 9 } 10 11 /// <summary> 12 /// 标识矩阵 13 /// </summary> 14 public class SPNode 15 { 16 //矩阵总行数 17 public int rows; 18 19 //矩阵总列数 20 public int cols; 21 22 //非零元素的个数 23 public int count; 24 25 //矩阵中非零元素 26 public List<Unit> nodes = new List<Unit>(); 27 }
其实说到这里也就差不多了,我们只要知道三元组是用来做矩阵压缩的一个顺序存储方式即可,然后知道怎么用三元组表来做一些常规的矩阵
运算,好了,既然说已经做成线性存储了,那就做个“行列置换”玩玩。
二:行列置换
做行列置换很容易,也就是交换"非零元素"的(x,y)坐标,要注意的就是,原先我们的三元组采用的是”行优先“,所以在做转置的时候需要
遵循"列优先“。
1 /// <summary> 2 /// 行转列运算 3 /// </summary> 4 /// <param name="spNode"></param> 5 /// <returns></returns> 6 public SPNode ConvertSpNode(SPNode spNode) 7 { 8 //矩阵元素的x和y坐标进行交换 9 SPNode spNodeLast = new SPNode(); 10 11 //行列互换 12 spNodeLast.rows = spNode.cols; 13 spNodeLast.cols = spNode.rows; 14 spNodeLast.count = spNode.count; 15 16 //循环原矩阵的列数 (行列转换) 17 for (int col = 0; col < spNode.cols; col++) 18 { 19 //循环三元组行的个数 20 for (int sp = 0; sp < spNode.count; sp++) 21 { 22 var single = spNode.nodes[sp]; 23 24 //找到三元组中存在的相同编号 25 if (col == single.y) 26 { 27 spNodeLast.nodes.Add(new Unit() 28 { 29 x = single.y, 30 y = single.x, 31 element = single.element 32 }); 33 } 34 } 35 } 36 37 return spNodeLast; 38 }
最后是总的代码:
View Code
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Diagnostics; 6 using System.Threading; 7 using System.IO; 8 9 namespace ConsoleApplication2 10 { 11 public class Program 12 { 13 public static void Main() 14 { 15 Martix martix = new Martix(); 16 17 //构建三元组 18 var node = martix.Build(); 19 20 foreach (var item in node.nodes) 21 { 22 Console.WriteLine(item.x + "\t" + item.y + "\t" + item.element); 23 } 24 25 Console.WriteLine("******************************************************"); 26 27 var mynode = martix.ConvertSpNode(node); 28 29 foreach (var item in mynode.nodes) 30 { 31 Console.WriteLine(item.x + "\t" + item.y + "\t" + item.element); 32 } 33 34 Console.Read(); 35 } 36 } 37 38 public class Martix 39 { 40 /// <summary> 41 /// 三元组 42 /// </summary> 43 public class Unit 44 { 45 public int x; 46 public int y; 47 public int element; 48 } 49 50 /// <summary> 51 /// 标识矩阵 52 /// </summary> 53 public class SPNode 54 { 55 //矩阵总行数 56 public int rows; 57 58 //矩阵总列数 59 public int cols; 60 61 //非零元素的个数 62 public int count; 63 64 //矩阵中非零元素 65 public List<Unit> nodes = new List<Unit>(); 66 } 67 68 /// <summary> 69 /// 构建一个三元组 70 /// </summary> 71 /// <returns></returns> 72 public SPNode Build() 73 { 74 SPNode spNode = new SPNode(); 75 76 //遵循行优先的原则 77 spNode.nodes.Add(new Unit() { x = 0, y = 0, element = 8 }); 78 spNode.nodes.Add(new Unit() { x = 1, y = 2, element = 1 }); 79 spNode.nodes.Add(new Unit() { x = 2, y = 3, element = 6 }); 80 spNode.nodes.Add(new Unit() { x = 3, y = 1, element = 4 }); 81 82 //4阶矩阵 83 spNode.rows = spNode.cols = 4; 84 85 //非零元素的个数 86 spNode.count = spNode.nodes.Count; 87 88 return spNode; 89 } 90 91 /// <summary> 92 /// 行转列运算 93 /// </summary> 94 /// <param name="spNode"></param> 95 /// <returns></returns> 96 public SPNode ConvertSpNode(SPNode spNode) 97 { 98 //矩阵元素的x和y坐标进行交换 99 SPNode spNodeLast = new SPNode(); 100 101 //行列互换 102 spNodeLast.rows = spNode.cols; 103 spNodeLast.cols = spNode.rows; 104 spNodeLast.count = spNode.count; 105 106 //循环原矩阵的列数 (行列转换) 107 for (int col = 0; col < spNode.cols; col++) 108 { 109 //循环三元组行的个数 110 for (int sp = 0; sp < spNode.count; sp++) 111 { 112 var single = spNode.nodes[sp]; 113 114 //找到三元组中存在的相同编号 115 if (col == single.y) 116 { 117 spNodeLast.nodes.Add(new Unit() 118 { 119 x = single.y, 120 y = single.x, 121 element = single.element 122 }); 123 } 124 } 125 } 126 127 return spNodeLast; 128 } 129 } 130 }