C#+无unsafe的非托管大数组示例详解(large unmanaged array in c# without ‘unsafe’ keyword)

C#申请一个大数组(Use a large array in C#)

在C#里,有时候我需要能够申请一个很大的数组、使用之、然后立即释放其占用的内存。

Sometimes I need to allocate a large array, use it and then release its memory space immediately.

由于在C#里提供的 int[] array = new int[1000000]; 这样的数组,其内存释放很难由程序员完全控制,在申请一个大数组后,程序可能会变得很慢。

If I use something like  int[] array = new int[1000000]; , it will be difficult to release its memory space by programmer and the app probably runs slower and slower.

特别是在C#+OpenGL编程中,我在使用VAO/VBO时十分需要设计一个非托管的数组,比如在glBufferData时我希望可以使用下面的glBufferData:

Specially in C#+OpenGL routines when I'm using VAO/VBO, I need an unmanaged array for glBufferData:

/// <summary>
 /// 设置当前VBO的数据。
 /// </summary>
 /// <param name="target"></param>
 /// <param name="data"></param>
 /// <param name="usage"></param>
 public static void glBufferData(uint target, UnmanagedArrayBase data, uint usage)
 {
 GetDelegateFor<glBufferData>()((uint)target,
 data.ByteLength, // 使用非托管数组
 data.Header, // 使用非托管数组
 (uint)usage);
 }
 // ...
 // glBufferData的声明
 private delegate void glBufferData(uint target, int size, IntPtr data, uint usage);

而在指定VBO的数据时,可能是float、vec3等等类型:

And the content in VBO can be float, vec3 and any other structs.

/// <summary>
 /// 金字塔的posotion array.
 /// </summary>
 static vec3[] positions = new vec3[]
 {
 new vec3(0.0f, 1.0f, 0.0f),
 new vec3(-1.0f, -1.0f, 1.0f),
 // ...
 new vec3(-1.0f, -1.0f, 1.0f),
 };
// Create a vertex buffer for the vertex data.
 {
 uint[] ids = new uint[1];
 GL.GenBuffers(1, ids);
 GL.BindBuffer(GL.GL_ARRAY_BUFFER, ids[0]);
 // 使用vec3作为泛型的非托管数组的参数
 UnmanagedArray<vec3> positionArray = new UnmanagedArray<vec3>(positions.Length);
 for (int i = 0; i < positions.Length; i++)
 {
  // 使用this[i]这样的索引方式来读写非托管数组的元素
  positionArray[i] = positions[i];
 }
 GL.BufferData(BufferDataTarget.ArrayBuffer, positionArray, BufferDataUsage.StaticDraw);
 GL.VertexAttribPointer(positionLocation, 3, GL.GL_FLOAT, false, 0, IntPtr.Zero);
 GL.EnableVertexAttribArray(positionLocation);
 }

UnmanagedArray<T>

所以我设计了这样一个非托管的数组类型:无unsafe,可接收任何struct类型作为泛型参数,可随时释放内存。

So I designed this UnmangedArray<T> : no 'unsafe' keyword, takes any struct as generic parameter, can be released anytime you want.

1 /// <summary>
 2 /// 元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct的非托管数组。
 3 /// <para>不能使用enum类型作为T。</para>
 4 /// </summary>
 5 /// <typeparam name="T">sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct, 不能使用enum类型作为T。</typeparam>
 6 public class UnmanagedArray<T> : UnmanagedArrayBase where T : struct
 7 {
 8
 9 /// <summary>
 10 ///元素类型为sbyte, byte, char, short, ushort, int, uint, long, ulong, float, double, decimal, bool或其它struct的非托管数组。
 11 /// </summary>
 12 /// <param name="count"></param>
 13 [MethodImpl(MethodImplOptions.Synchronized)]
 14 public UnmanagedArray(int count)
 15 : base(count, Marshal.SizeOf(typeof(T)))
 16 {
 17 }
 18
 19 /// <summary>
 20 /// 获取或设置索引为<paramref name="index"/>的元素。
 21 /// </summary>
 22 /// <param name="index"></param>
 23 /// <returns></returns>
 24 public T this[int index]
 25 {
 26 get
 27 {
 28  if (index < 0 || index >= this.Count)
 29  throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 30
 31  var pItem = this.Header + (index * elementSize);
 32  //var obj = Marshal.PtrToStructure(pItem, typeof(T));
 33  //T result = (T)obj;
 34  T result = Marshal.PtrToStructure<T>(pItem);// works in .net 4.5.1
 35  return result;
 36 }
 37 set
 38 {
 39  if (index < 0 || index >= this.Count)
 40  throw new IndexOutOfRangeException("index of UnmanagedArray is out of range");
 41
 42  var pItem = this.Header + (index * elementSize);
 43  //Marshal.StructureToPtr(value, pItem, true);
 44  Marshal.StructureToPtr<T>(value, pItem, true);// works in .net 4.5.1
 45 }
 46 }
 47
 48 /// <summary>
 49 /// 按索引顺序依次获取各个元素。
 50 /// </summary>
 51 /// <returns></returns>
 52 public IEnumerable<T> GetElements()
 53 {
 54 if (!this.disposed)
 55 {
 56  for (int i = 0; i < this.Count; i++)
 57  {
 58  yield return this[i];
 59  }
 60 }
 61 }
 62 }
 63
 64 /// <summary>
 65 /// 非托管数组的基类。
 66 /// </summary>
 67 public abstract class UnmanagedArrayBase : IDisposable
 68 {
 69
 70 /// <summary>
 71 /// 数组指针。
 72 /// </summary>
 73 public IntPtr Header { get; private set; }
 74
 75 /// <summary>
 76 /// 元素数目。
 77 /// </summary>
 78 public int Count { get; private set; }
 79
 80 /// <summary>
 81 /// 单个元素的字节数。
 82 /// </summary>
 83 protected int elementSize;
 84
 85 /// <summary>
 86 /// 申请到的字节数。(元素数目 * 单个元素的字节数)。
 87 /// </summary>
 88 public int ByteLength
 89 {
 90 get { return this.Count * this.elementSize; }
 91 }
 92
 93
 94 /// <summary>
 95 /// 非托管数组。
 96 /// </summary>
 97 /// <param name="elementCount">元素数目。</param>
 98 /// <param name="elementSize">单个元素的字节数。</param>
 99 [MethodImpl(MethodImplOptions.Synchronized)]
100 protected UnmanagedArrayBase(int elementCount, int elementSize)
101 {
102 this.Count = elementCount;
103 this.elementSize = elementSize;
104
105 int memSize = elementCount * elementSize;
106 this.Header = Marshal.AllocHGlobal(memSize);
107
108 allocatedArrays.Add(this);
109 }
110
111 private static readonly List<IDisposable> allocatedArrays = new List<IDisposable>();
112
113 /// <summary>
114 /// 立即释放所有<see cref="UnmanagedArray"/>。
115 /// </summary>
116 [MethodImpl(MethodImplOptions.Synchronized)]
117 public static void FreeAll()
118 {
119 foreach (var item in allocatedArrays)
120 {
121  item.Dispose();
122 }
123 allocatedArrays.Clear();
124 }
125
126 ~UnmanagedArrayBase()
127 {
128 Dispose();
129 }
130
131 #region IDisposable Members
132
133 /// <summary>
134 /// Internal variable which checks if Dispose has already been called
135 /// </summary>
136 protected Boolean disposed;
137
138 /// <summary>
139 /// Releases unmanaged and - optionally - managed resources
140 /// </summary>
141 /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
142 protected void Dispose(Boolean disposing)
143 {
144 if (disposed)
145 {
146  return;
147 }
148
149 if (disposing)
150 {
151  //Managed cleanup code here, while managed refs still valid
152 }
153 //Unmanaged cleanup code here
154 IntPtr ptr = this.Header;
155
156 if (ptr != IntPtr.Zero)
157 {
158  this.Count = 0;
159  this.Header = IntPtr.Zero;
160  Marshal.FreeHGlobal(ptr);
161 }
162
163 disposed = true;
164 }
165
166 /// <summary>
167 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
168 /// </summary>
169 public void Dispose()
170 {
171 this.Dispose(true);
172 GC.SuppressFinalize(this);
173 }
174
175 #endregion
176
177 }

UnmanagedArray

如何使用(How to use)

UnmanagedArray<T>使用方式十分简单,就像一个普通的数组一样:

Using UnamangedAray<T> is just like a normal array(int[], vec3[], etc.):

internal static void TypicalScene()
 {
 const int count = 100;

 // 测试float类型
 var floatArray = new UnmanagedArray<float>(count);
 for (int i = 0; i < count; i++)
 {
 floatArray[i] = i;
 }
 for (int i = 0; i < count; i++)
 {
 var item = floatArray[i];
 if (item != i)
 { throw new Exception(); }
 }

 // 测试int类型
 var intArray = new UnmanagedArray<int>(count);
 for (int i = 0; i < count; i++)
 {
 intArray[i] = i;
 }
 for (int i = 0; i < count; i++)
 {
 var item = intArray[i];
 if (item != i)
 { throw new Exception(); }
 }

 // 测试bool类型
 var boolArray = new UnmanagedArray<bool>(count);
 for (int i = 0; i < count; i++)
 {
 boolArray[i] = i % 2 == 0;
 }
 for (int i = 0; i < count; i++)
 {
 var item = boolArray[i];
 if (item != (i % 2 == 0))
 { throw new Exception(); }
 }

 // 测试vec3类型
 var vec3Array = new UnmanagedArray<vec3>(count);
 for (int i = 0; i < count; i++)
 {
 vec3Array[i] = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
 }
 for (int i = 0; i < count; i++)
 {
 var item = vec3Array[i];
 var old = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
 if (item.x != old.x || item.y != old.y || item.z != old.z)
 { throw new Exception(); }
 }

 // 测试foreach
 foreach (var item in vec3Array.GetElements())
 {
 Console.WriteLine(item);
 }

 // 释放此数组占用的内存,这之后就不能再使用vec3Array了。
 vec3Array.Dispose();

 // 立即释放所有非托管数组占用的内存,这之后就不能再使用上面申请的数组了。
 UnmanagedArrayBase.FreeAll();
 }

快速读写UnmanagedArray<T>

UnmanagedArrayHelper

由于很多时候需要申请和使用很大的UnmanagedArray<T>,直接使用this[index]索引方式速度会偏慢,所以我添加了几个辅助方法,专门解决快速读写UnmanagedArray<T>的问题。

public static class UnmanagedArrayHelper
 {
 ///// <summary>
 ///// 错误 1 无法获取托管类型(“T”)的地址和大小,或无法声明指向它的指针
 ///// </summary>
 ///// <typeparam name="T"></typeparam>
 ///// <param name="array"></param>
 ///// <returns></returns>
 //public static unsafe T* FirstElement<T>(this UnmanagedArray<T> array) where T : struct
 //{
 // var header = (void*)array.Header;
 // return (T*)header;
 //}

 /// <summary>
 /// 获取非托管数组的第一个元素的地址。
 /// </summary>
 /// <param name="array"></param>
 /// <returns></returns>
 public static unsafe void* FirstElement(this UnmanagedArrayBase array)
 {
 var header = (void*)array.Header;

 return header;
 }

 public static unsafe void* LastElement(this UnmanagedArrayBase array)
 {
 var last = (void*)(array.Header + (array.ByteLength - array.ByteLength / array.Length));

 return last;
 }

 /// <summary>
 /// 获取非托管数组的最后一个元素的地址再向后一个单位的地址。
 /// </summary>
 /// <param name="array"></param>
 /// <returns></returns>
 public static unsafe void* TailAddress(this UnmanagedArrayBase array)
 {
 var tail = (void*)(array.Header + array.ByteLength);

 return tail;
 }
 }

如何使用

这个类型实现了3个扩展方法,可以获取UnmanagedArray<T>的第一个元素的位置、最后一个元素的位置、最后一个元素+1的位置。用这种unsafe的方法可以实现C语言一样的读写速度。

下面是一个例子。用unsafe的方式读写UnmanagedArray<T>,速度比this[index]方式快10到70倍。

public static void TypicalScene()
 {
 int length = 1000000;
 UnmanagedArray<int> array = new UnmanagedArray<int>(length);
 UnmanagedArray<int> array2 = new UnmanagedArray<int>(length);

 long tick = DateTime.Now.Ticks;
 for (int i = 0; i < length; i++)
 {
 array[i] = i;
 }
 long totalTicks = DateTime.Now.Ticks - tick;

 tick = DateTime.Now.Ticks;
 unsafe
 {
 int* header = (int*)array2.FirstElement();
 int* last = (int*)array2.LastElement();
 int* tailAddress = (int*)array2.TailAddress();
 int value = 0;
 for (int* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++)
 {
  *ptr = value++;
 }
 }
 long totalTicks2 = DateTime.Now.Ticks - tick;
 Console.WriteLine("ticks: {0}, {1}", totalTicks, totalTicks2);// unsafe method works faster.

 for (int i = 0; i < length; i++)
 {
 if (array[i] != i)
 {
  Console.WriteLine("something wrong here");
 }
 if (array2[i] != i)
 {
  Console.WriteLine("something wrong here");
 }
 }

 array.Dispose();
 array2.Dispose();
 }
unsafe
 {
  vec3* header = (vec3*)vec3Array.FirstElement();
  vec3* last = (vec3*)vec3Array.LastElement();
  vec3* tailAddress = (vec3*)vec3Array.TailAddress();
  int i = 0;
  for (vec3* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++)
  {
  *ptr = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
  i++;
  }
  i = 0;
  for (vec3* ptr = header; ptr <= last/*or: ptr < tailAddress*/; ptr++, i++)
  {
  var item = *ptr;
  var old = new vec3(i * 3 + 0, i * 3 + 1, i * 3 + 2);
  if (item.x != old.x || item.y != old.y || item.z != old.z)
  { throw new Exception(); }
  }
 }

2015-08-25

用StructLayout和MarshalAs支持复杂的struct

在OpenGL中我需要用UnmanagedArray<mat4>,其中mat4定义如下:

1 /// <summary>
 2 /// Represents a 4x4 matrix.
 3 /// </summary>
 4 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4 * 4)]
 5 public struct mat4
 6 {
 7 /// <summary>
 8 /// Gets or sets the <see cref="vec4"/> column at the specified index.
 9 /// </summary>
10 /// <value>
11 /// The <see cref="vec4"/> column.
12 /// </value>
13 /// <param name="column">The column index.</param>
14 /// <returns>The column at index <paramref name="column"/>.</returns>
15 public vec4 this[int column]
16 {
17 get { return cols[column]; }
18 set { cols[column] = value; }
19 }
20
21 /// <summary>
22 /// Gets or sets the element at <paramref name="column"/> and <paramref name="row"/>.
23 /// </summary>
24 /// <value>
25 /// The element at <paramref name="column"/> and <paramref name="row"/>.
26 /// </value>
27 /// <param name="column">The column index.</param>
28 /// <param name="row">The row index.</param>
29 /// <returns>
30 /// The element at <paramref name="column"/> and <paramref name="row"/>.
31 /// </returns>
32 public float this[int column, int row]
33 {
34 get { return cols[column][row]; }
35 set { cols[column][row] = value; }
36 }
37
38 /// <summary>
39 /// The columms of the matrix.
40 /// </summary>
41 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
42 private vec4[] cols;
43 }
44
45 /// <summary>
46 /// Represents a four dimensional vector.
47 /// </summary>
48 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4)]
49 public struct vec4
50 {
51 public float x;
52 public float y;
53 public float z;
54 public float w;
55
56 public float this[int index]
57 {
58 get
59 {
60  if (index == 0) return x;
61  else if (index == 1) return y;
62  else if (index == 2) return z;
63  else if (index == 3) return w;
64  else throw new Exception("Out of range.");
65 }
66 set
67 {
68  if (index == 0) x = value;
69  else if (index == 1) y = value;
70  else if (index == 2) z = value;
71  else if (index == 3) w = value;
72  else throw new Exception("Out of range.");
73 }
74 }
75 }

mat4

注意:UnmanagedArray<T>支持的struct,T的大小必须是确定的。所以在mat4里我们用 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4 * 4)] 指定mat4的大小为4个 vec4 * 4个 float * 4个字节(每个float) = 64字节,并且在 private vec4[] cols; 上用 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 规定了cols的元素数必须是4。之后在 vec4 上的 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 4 * 4)] 不写也可以,因为vec4只有4个简单的float字段,不含复杂类型。

下面是测试用例。

mat4 matrix = glm.scale(mat4.identity(), new vec3(2, 3, 4));

 var size = Marshal.SizeOf(typeof(mat4));
 size = Marshal.SizeOf(matrix);

 UnmanagedArray<mat4> array = new UnmanagedArray<mat4>(1);
 array[0] = matrix;

 mat4 newMatirx = array[0]; // newMatrix should be equal to matrix

 array.Dispose();

如果matrix和newMatrix相等,就说明上述Attribute配置正确了。

总结

到此这篇关于C#+无unsafe的非托管大数组(large unmanaged array in c# without 'unsafe' keyword)的文章就介绍到这了,更多相关C#+无unsafe的非托管大数组内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • c#获取数组中最大数的值

    求数组中最大的数的值:1.数组的max函数: 复制代码 代码如下: class Program    {        static void Main(string[] args)        {            int[] array = {1,3,5,2,4,6,7,9,0,8};           int max= GetMax(array);            Console.WriteLine("数组中最大的值是{0}",max);            Co

  • C#动态调整数组大小的方法

    本文实例讲述了C#动态调整数组大小的方法.分享给大家供大家参考.具体如下: 通常,我们创建一个数组后就不能调整其长度,但是Array类提供了一个静态方法CreateInstance用来创建一个动态数组,所以我们可以通过它来动态调整数组的长度. namespace ArrayManipulation { Class Program { static void Main (String[] args) { int[] arr = new int[]{1,2,3}; PrintArr(arr); ar

  • C#实现char字符数组与字符串相互转换的方法

    本文实例讲述了C#实现char字符数组与字符串相互转换的方法.分享给大家供大家参考,具体如下: 一.字符串转换为字符数组 char[] tempChar = sourceString.ToCharArray(); 二.字符数组转换为字符串 //方法一 string str = string.Join("", tempChar); //方法二 string str = string.Concat<char>(tempChar); //方法三 string str = new

  • c#数组详解

    数组是一种数据结构,其声明方式如下: type[] arrayName; 数组具有以下属性: 1.数组可以是一维.多维或交错的.     2.数值数组元素的默认值设置为零,而引用元素的默认值设置为 null.     3.交错数组是数组的数组,因此,它的元素是引用类型,初始化为 null.     4.数组的索引从零开始:具有 n 个元素的数组的索引是从 0 到 n-1.     5.数组元素可以是任何类型,包括数组类型. 一维数组 //声明一维数组,没有初始化,等于null int[] int

  • C#二维数组基本用法实例

    本文实例讲述了C#二维数组基本用法.分享给大家供大家参考,具体如下: //定义数组 string[,] classes = new string[5, 2]; //正确的C#二维数组使用方法 classes[i, 0] = ""; //错误的使用方法 classes[i][0]=""; 据说这种形式的C#二维数组叫做锯齿数组, 一段例子以供参考: // 声明一个锯齿型数组,该数组有两个元素 int[][] myArray = new int[2][]; // 其中第

  • C#+无unsafe的非托管大数组示例详解(large unmanaged array in c# without ‘unsafe’ keyword)

    C#申请一个大数组(Use a large array in C#) 在C#里,有时候我需要能够申请一个很大的数组.使用之.然后立即释放其占用的内存. Sometimes I need to allocate a large array, use it and then release its memory space immediately. 由于在C#里提供的 int[] array = new int[1000000]; 这样的数组,其内存释放很难由程序员完全控制,在申请一个大数组后,程序

  • C#中托管DLL和非托管DLL的区别详解

    首先解释一下,托管DLL和非托管DLL的区别.狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件.非托管DLL不是在Dotnet环境生成的DLL文件. 托管DLL文件,可以在Dotnet环境通过 "添加引用" 的方式,直接把托管DLL文件添加到项目中.然后通过 Using DLL命 名空间,来调用相应的DLL对象 .  非托管DLL文件,在Dotnet环境应用时,通过 DllImport 调用. C# 调用非托管DLL文件.DLL文件是用C语言编写的. 托管DLL就是能够在公共

  • java数据结构算法稀疏数组示例详解

    目录 一.什么是稀疏数组 二.场景用法 1.二维数组转稀疏数组思路 2.稀疏数组转二维数组思路 3.代码实现 一.什么是稀疏数组 当一个数组a中大部分元素为0,或者为同一个值,那么可以用稀疏数组b来保存数组a. 首先,稀疏数组是一个数组,然后以一种特定的方式来保存上述的数组a,具体处理方法: 记录数组a一共有几行几列 记录a中有多少个不同的值 最后记录不同值的元素所在行列,以及具体的值,放在一个小规模的数组里,以缩小程序的规模. 这个小规模的数组,就是稀疏数组. 举个栗子,左侧是一个二维数组,一

  • C语言动态内存管理malloc柔性数组示例详解

    目录 1.1为什么存在动态内存管理 1.2动态内存管理函数 1.2.1malloc 1.2.2free 1.2.3calloc 1.2.4realloc 1.3动态内存管理函数易错点 1.3.1对NULL指针的解引用操作 1.3.2对动态开辟空间的越界访问 1.3.3对非动态开辟内存使用free释放 1.3.4使用free释放一块动态开辟内存的一部分 1.3.5对同一块动态内存多次释放 1.3.6动态开辟内存忘记释放(内存泄漏) 2.1常见相关笔试题 2.2C/C++语言中的内存开辟 2.3柔性

  • Python 异步之非阻塞流使用示例详解

    目录 1. 异步流 2. 如何打开连接 3. 如何启动服务器 4. 如何使用 StreamWriter 写入数据 5. 如何使用 StreamReader 读取数据 6. 如何关闭连接 1. 异步流 asyncio 的一个主要好处是能够使用非阻塞流. Asyncio 提供非阻塞 I/O 套接字编程.这是通过流提供的. 可以打开提供对流写入器和流写入器的访问的套接字.然后可以使用协同程序从流中写入和读取数据,并在适当的时候暂停.完成后,可以关闭套接字. 异步流功能是低级的,这意味着必须手动实现所需

  • sun unsafe类功能及使用注意事项详解

    目录 Unsafe简介 获取Unsafe实例 Unsafe功能列表 Unsafe的数组操作 base offset含义 index scale含义 array copy to direct memory copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) Benchmark 什么时候用Unsafe Unsafe简介 Unsafe是位于sun.misc包下的一个类,主要提供

  • C语言中指针和数组试题详解分析

    目录 数组题: 程序一(一维数组): 字符数组 程序二(字符数组): 程序三(字符数组): 程序四(字符数组): 程序五(字符数组): 二维数组 程序六( 二维数组): 指针题 程序七( 指针): 程序八( 指针): 程序九( 指针): 程序十( 指针): 程序十( 图): 程序十一( 指针): 程序十二( 指针): 程序十三( 指针): 指针 和 数组 试题解析 小编,在这里想说一下,c语言的最后一节 C预处理,可能还需要一些时间,因为小编,昨天才下载了虚拟机 和 linux 系统,还没开始安

  • Java数据结构实现二维数组与稀疏数组转换详解

    基本介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组. 稀疏数组的处理方法是: ①记录数组一共有几行几列,有多少个不同的值(0除外). ②把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模. 二维数组转稀疏数组: ①遍历原始的二维数组,得到有效数据的个数 sum(除0外不同值) ②根据 sum 创建稀疏数组 sparseArr int[sum+1][3] ③将二维数组的有效数据数据存入到稀疏数组 (稀疏数组的第一行,三列分别记录二维数组

  • C语言 指针数组进阶详解

    目录 指针与数组中的sizeof与strlen sizeof strlen 数组名 1.一维数组 整型数组 字符数组 指针数组 2.二维数组 指针笔试题 笔试题1 笔试题2 笔试题3 笔试题4 笔试题5 前言:指针与数组的知识往往让我们无法给自己定位,似乎是懂了,但真的碰上了又一言难尽.接下来有一些关于指针与数组的知识和例题讲解,来看看你对指针和数组到底有多了解吧! 指针与数组中的sizeof与strlen sizeof sizeof值关注占用空间的大小,单位是字节,不关注元素的类型,是一个操作

  • 可能是你看过最全的十大排序算法详解(完整版代码)

    目录 前言 交集排序 冒泡 简单 快速排序 插入排序 直接插入排序 希尔排序 选择排序 简单选择排序 堆排序 归并排序 二路 多路 非比较类 计数排序 桶排序 基数排序 最后 前言 兄弟们,应上篇数据结构的各位要求,今天我开始工作了,开始肝算法,剑指offer还在路上,我真想开车去接它,奈何码神没有驾照的开车,算了,弄排序算法吧,有点长,耐心看啊,原创不易,你们懂的,先上一张图 可以看出排序算法,还是比较多的,算了,不多说了,你我肝完就是出门自带4年实习经验的! 交集排序 冒泡 冒泡我一般也将它

随机推荐