Implementierung einer vernetzten Liste basierend auf C#

Im letzten Artikel haben wir uns mit der sequentiellen Speicherung von Matrizen befasst. In diesem Artikel werden wir uns mit der verknüpften Speichermethode „Cross Linked List“ befassen. Der Zweck ist natürlich derselbe, nämlich Platz zu komprimieren.

1. Konzept

Da wir verknüpfte Listenknoten verwenden möchten, um Nicht-Null-Elemente in der Matrix zu simulieren, benötigen wir auf jeden Fall die folgenden 5 Elemente (Zeile, Spalte, Wert, unten, rechts), darunter:

row:矩阵中的行。
col:矩阵中的列。
val:矩阵中的值。
right:指向右侧的一个非零元素。
down:指向下侧的一个非零元素。

Bild.png
Nachdem wir nun wissen, wie ein einzelner Knoten dargestellt werden sollte, stellt sich die Frage, ob die Darstellung der Nicht-Null-Elemente derselben Zeile in der Matrix nicht eine einfach verknüpfte Liste ist? Zum Beispiel wie folgt:
Bild.png
Ist die Darstellung eines mehrzeiligen Nicht-Null-Elements dann nicht nur mehrere einfach verknüpfte Listen? Ja, hier mache ich aus der einfach verknüpften Liste eine zirkulär verknüpfte Liste. Werfen wir einen Blick darauf wie man eine vernetzte Liste zur Darstellung einer dünn besetzten Matrix verwendet.
Bild.png
Bei der obigen vernetzten Liste sind zwei Probleme zu beachten:
Erstens: Hier gibt es einen farbigen Knoten, der den Zusammenfassungspunkt in der vernetzten Liste darstellt. Er zeichnet (Zeile, Spalte, Wert) in der Matrix und den Punkten auf zum nächsten Der nächste Zeiger des Kopfknotens.
Zweitens: Jede verknüpfte Liste verfügt über einen Kopfzeiger, und der Zusammenfassungspunkt verwendet den nächsten Zeiger, um sie zu verbinden.

2. Betrieb

2.1. Datenstruktur

Wie gerade erwähnt, verfügt der Zusammenfassungspunkt der vernetzten Liste über einen nächsten Zeiger, andere Knoten ungleich Null jedoch nicht. Daher umschließen wir ihn der Einfachheit halber mit einer Unit-Klasse.

 #region 单一节点
 /// <summary>
 /// 单一节点
 /// </summary>
 public class Node
 {
    
    
     //行号
     public int rows;

     //列号
     public int cols;

     //向下的指针域
     public Node down;

     //向右的指针域
     public Node right;

     //单元值(头指针的next和val)
     public Unit unit;
 }
 #endregion

 #region 统一“表头节点”和“非零节点”
 /// <summary>
 /// 统一“表头节点”和“非零节点”
 /// </summary>
 public class Unit
 {
    
    
     //表头节点的next域
     public Node next;

     //非零元素的值
     public int value;
 }
 #endregion

2.2. Initialisierung

In diesem Schritt initialisieren wir den Zusammenfassungspunkt und verwenden den nächsten Zeiger, um den Kopfknoten jeder einfach verknüpften Liste zu einer einfach verknüpften Liste zu verknüpfen (d. h. die erste Zeile der vernetzten Liste in der obigen Abbildung).

#region 十字链表中的“行数,列数,非零元素个数”
 /// <summary>
 /// 十字链表中的“行数,列数,非零元素个数”
 /// </summary>
 /// <param name="rows"></param>
 /// <param name="cols"></param>
 /// <param name="count"></param>
 public void Init(int rows, int cols, int count)
 {
    
    
     var len = Math.Max(rows, cols) + 1;

     //从下标1开始算起
     nodes = new Node[len];

     //十字链表的总头节点
     nodes[0] = new Node();

     nodes[0].rows = rows;
     nodes[0].cols = cols;
     nodes[0].unit = new Unit()
     {
    
    
         value = count,
         next = null,
     };

     //down和right都指向自身
     nodes[0].right = nodes[0];
     nodes[0].down = nodes[0];

     var temp = nodes[0];

     //初始化多条链表的头结点
     for (int i = 1; i < len; i++)
     {
    
    
         nodes[i] = new Node();

         nodes[i].rows = 0;
         nodes[i].cols = 0;
         nodes[i].unit = new Unit()
         {
    
    
             value = 0,
             next = temp.unit.next
         };

         //给上一个节点的next域赋值
         temp.unit.next = nodes[i];

         //将当前节点作为下一次循环的上一个节点
         temp = nodes[i];

         nodes[i].right = nodes[i];
         nodes[i].down = nodes[i];
     }
 }
 #endregion

2.3. Knoten einfügen

Fügen Sie einfach den Knoten entsprechend der Zeile und Spalte des eingefügten Knotens an der angegebenen Position in der vernetzten Liste ein.

#region 插入十字链表中
 /// <summary>
 /// 插入十字链表中
 /// </summary>
 /// <param name="nums">矩阵</param>
 /// <param name="rows">矩阵的行数</param>
 /// <param name="cols">矩阵的列数</param>
 /// <param name="count">非0元素个数</param>
 /// <returns></returns>
 public Node[] Insert(int[,] nums, int rows, int cols, int count)
 {
    
    
     //初始化操作
     Init(rows, cols, count);

     //插入操作
     for (int i = 0; i < rows; i++)
     {
    
    
         for (int j = 0; j < cols; j++)
         {
    
    
             //直插入"非0元素"
             if (nums[i, j] != 0)
             {
    
    
                 var node = new Node();

                 node.rows = i + 1;
                 node.cols = j + 1;
                 node.unit = new Unit()
                 {
    
    
                     value = nums[i, j]
                 };
                 node.right = node;
                 node.down = node;

                 InsertNode(node);
             }
         }
     }

     return nodes;
 }
 #endregion

2.4. Verlinkte Liste drucken

Wir müssen nur den rechten Zeiger jeder Zeile der verknüpften Liste durchlaufen.

#region 打印十字链表
 /// <summary>
 /// 打印十字链表
 /// </summary>
 /// <param name="nodes"></param>
 public void Print(Node[] nodes)
 {
    
    
     var head = nodes[0];

     //遍历每一行的right
     for (int i = 1; i < head.rows + 1; i++)
     {
    
    
         var p = nodes[i];

         while (p.right != nodes[i])
         {
    
    
             Console.WriteLine("({0},{1})\tval => {2}",
                 p.right.rows,
                 p.right.cols,
                 p.right.unit.value);

             //指向下一个节点
             p = p.right;
         }
     }
 }
 #endregion

2.5. Gesamtcode:

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Diagnostics;
 using System.Threading;
 using System.IO;
 
 namespace ConsoleApplication2
 {
    
    
     public class Program
     {
    
    
         public static void Main()
         {
    
    
             Crosslist crosslist = new Crosslist();
 
             int[,] nums = {
    
    
             {
    
    2,0,4 },
             {
    
    0,3,0 },
             {
    
    0,0,9 }
            };
 
             var nodes = crosslist.Insert(nums, 3, 3, 4);
 
             crosslist.Print(nodes);
 
             Console.Read();
         }
     }
 
     /// <summary>
     /// 十字链表
     /// </summary>
     public class Crosslist
     {
    
    
         #region 单一节点
         /// <summary>
         /// 单一节点
         /// </summary>
         public class Node
         {
    
    
             //行号
             public int rows;
 
             //列号
             public int cols;
 
             //向下的指针域
             public Node down;
 
             //向右的指针域
             public Node right;
 
             //单元值(头指针的next和val)
             public Unit unit;
         }
         #endregion
 
         #region 统一“表头节点”和“非零节点”
         /// <summary>
         /// 统一“表头节点”和“非零节点”
         /// </summary>
         public class Unit
         {
    
    
             //表头节点的next域
             public Node next;
 
             //非零元素的值
             public int value;
         }
         #endregion
 
         Node[] nodes;
 
         #region 十字链表中的“行数,列数,非零元素个数”
         /// <summary>
         /// 十字链表中的“行数,列数,非零元素个数”
         /// </summary>
         /// <param name="rows"></param>
         /// <param name="cols"></param>
         /// <param name="count"></param>
         public void Init(int rows, int cols, int count)
         {
    
    
             var len = Math.Max(rows, cols) + 1;
 
             //从下标1开始算起
             nodes = new Node[len];
 
             //十字链表的总头节点
             nodes[0] = new Node();
 
             nodes[0].rows = rows;
             nodes[0].cols = cols;
             nodes[0].unit = new Unit()
             {
    
    
                 value = count,
                 next = null,
             };
 
             //down和right都指向自身
             nodes[0].right = nodes[0];
             nodes[0].down = nodes[0];
 
             var temp = nodes[0];
 
             //初始化多条链表的头结点
             for (int i = 1; i < len; i++)
             {
    
    
                 nodes[i] = new Node();
 
                 nodes[i].rows = 0;
                 nodes[i].cols = 0;
                 nodes[i].unit = new Unit()
                 {
    
    
                     value = 0,
                     next = temp.unit.next
                 };
 
                 //给上一个节点的next域赋值
                 temp.unit.next = nodes[i];
 
                 //将当前节点作为下一次循环的上一个节点
                 temp = nodes[i];
 
                 nodes[i].right = nodes[i];
                 nodes[i].down = nodes[i];
             }
         }
         #endregion
 
         #region 在指定的“行,列”上插入节点
         /// <summary>
         /// 在指定的“行,列”上插入节点
         /// </summary>
         /// <param name="node"></param>
         /// <returns></returns>
         public void InsertNode(Node node)
         {
    
    
             //先定位行
             Node pnode = nodes[node.rows];
 
             //在指定的“行”中找,一直找到该行最后一个节点(right指针指向自己的为止)
             while (pnode.right != nodes[node.rows] && pnode.right.cols < node.cols)
                 pnode = pnode.right;
 
             //将最后一个节点的right指向插入节点的right,以此达到是循环链表
             node.right = pnode.right;
 
             //将插入节点给最后一个节点的right指针上
             pnode.right = node;
 
             //再定位列
             pnode = nodes[node.cols];
 
             //同理
             while (pnode.down != nodes[node.cols] && pnode.down.rows < node.rows)
             {
    
    
                 pnode = pnode.down;
             }
 
             node.down = pnode.down;
             pnode.down = node;
         }
         #endregion
 
         #region 插入十字链表中
         /// <summary>
         /// 插入十字链表中
         /// </summary>
         /// <param name="nums">矩阵</param>
         /// <param name="rows">矩阵的行数</param>
         /// <param name="cols">矩阵的列数</param>
         /// <param name="count">非0元素个数</param>
         /// <returns></returns>
         public Node[] Insert(int[,] nums, int rows, int cols, int count)
         {
    
    
             //初始化操作
             Init(rows, cols, count);
 
             //插入操作
             for (int i = 0; i < rows; i++)
             {
    
    
                 for (int j = 0; j < cols; j++)
                 {
    
    
                     //直插入"非0元素"
                     if (nums[i, j] != 0)
                     {
    
    
                         var node = new Node();
 
                         node.rows = i + 1;
                         node.cols = j + 1;
                         node.unit = new Unit()
                         {
    
    
                             value = nums[i, j]
                         };
                         node.right = node;
                         node.down = node;
 
                         InsertNode(node);
                     }
                 }
             }
 
             return nodes;
         }
         #endregion
 
         #region 打印十字链表
         /// <summary>
         /// 打印十字链表
         /// </summary>
         /// <param name="nodes"></param>
         public void Print(Node[] nodes)
         {
    
    
             var head = nodes[0];
 
             //遍历每一行的right
             for (int i = 1; i < head.rows + 1; i++)
             {
    
    
                 var p = nodes[i];
 
                 while (p.right != nodes[i])
                 {
    
    
                     Console.WriteLine("({0},{1})\tval => {2}",
                         p.right.rows,
                         p.right.cols,
                         p.right.unit.value);
 
                     //指向下一个节点
                     p = p.right;
                 }
             }
         }
         #endregion
     }
 }

Bild.png

おすすめ

転載: blog.csdn.net/s1t16/article/details/134640655
おすすめ