1 数组
1.1 C#中的数组
静态数组:int[] float[] double[] char[] string[]
特点:创建后容量无法改变
例如:
int[] arr = new int[10]
动态数组:ArrayList List(泛型)
特点:根据元素的数量,动态地调整数组的容量大小
class Program
{
static void Main(string[] args)
{
//数组
int[] arr = new int[10];
for (int i = 0; i < 10; i++)
{
arr[i] = i;
Console.Write(arr[i] + " ");
}
Console.WriteLine();
//动态数组ArrayList
ArrayList a = new ArrayList(10);
for (int i = 0; i < 15; i++)
{
a.Add(i);
Console.Write(a[i] + " ");
}
Console.WriteLine();
//泛型动态数组
List<int> l = new List<int>(10);
for (int i = 0; i < 15; i++)
{
l.Add(i);
Console.Write(l[i] + " ");
}
Console.Read();
}
}
1.2 实现一个存储整型元素的动态数组
using System;
using System.Collections.Generic;
using System.Text;
namespace DataStructure
{
class Array1//编写动态数组框架
{
private int[] data;//存储元素的静态数组data
private int N;//存储元素个数N
public Array1(int capacity)//有参构造
{
data = new int[capacity];
N = 0;
}
public Array1() : this(10) { }//无参构造
//public Array1()
//{
// data = new int[10];
// N = 0;
//}
private void ResetCapacity(int newCapacity)//重构数组容量,并把原有元素存储
{
int[] newData = new int[newCapacity];
for (int i = 0; i < N; i++)
newData[i] = data[i];
data = newData;
}
public int Capacity//获取数组容量
{
get { return data.Length; }
}
public int Count//获取数组元素个数
{
get { return N; }
}
public bool IsEmpty//判断数组是否为空
{
get { return N == 0; }
}
public void Add(int index,int e)//添加元素到数组中的指定索引位置
{
if (index < 0 || index > N)//判断索引位置是否合法
throw new ArgumentException("数组索引越界");
if (N == data.Length)//判断数组容量是否满了
ResetCapacity(2 * data.Length);
for (int i= N-1;i >= index; i--)//从数组末尾向后移动元素
data[i + 1] = data[i];
data[index] = e;
N++;
}
public void AddLast(int e)//数组末尾添加元素
{
Add(N, e);
}
public void AddFirst(int e)//数组头部添加元素
{
Add(0, e);
}
public int Get(int index)//获取指定索引位置元素
{
if (index < 0 || index >= N)
throw new ArgumentException("数组索引越界");
return data[index];
}
public int GetFirst()//获取首个元素
{
return Get(0);
}
public int GetLast()//获取末尾元素
{
return Get(N - 1);
}
public void Set(int index,int newE)//修改指定索引的元素
{
if (index < 0 || index >= N)
throw new ArgumentException("数组索引越界");
data[index] = newE;
}
public bool Contains(int e)//是否包含元素
{
for (int i = 0; i < N; i++)
{
if (data[i] == e)
return true;
}
return false;
}
public int IndexOf(int e)//搜索元素的索引
{
for (int i = 0; i < N; i++)
{
if (data[i] == e)
return i;
}
return -1;//找不到元素,返回-1
}
public int RemoveAt(int index)//删除指定索引的元素
{
if (index < 0 || index >= N)
throw new ArgumentException("索引超出了数组界限");
int del = data[index];
for (int i = index + 1; i <= N - 1; i++)//元素前移
data[i - 1] = data[i];
N--;
data[N] = default(int);//释放末尾位置元素
if (N == data.Length / 4)//数组长度只剩原来的四分之一,数组容量缩减
ResetCapacity(data.Length / 2);
return del;
}
public int RemoveFirst()
{
return RemoveAt(0);
}
public int RemoveLast()
{
return RemoveAt(N - 1);
}
public void Remove(int e)//删除指定元素
{
int index = IndexOf(e);
if (index != -1)
RemoveAt(index);
}
public override string ToString()//打印数组
{
StringBuilder res = new StringBuilder();
res.Append(string.Format("Array1: count={0} capacity={1}\n", N, data.Length));
res.Append("[");
for (int i = 0; i < N; i++)
{
res.Append(data[i]);
if (i != N - 1)
res.Append(", ");
}
res.Append("]");
return res.ToString();
}
}
}
Main调用:
namespace DataStructure
{
class Program
{
static void Main(string[] args)
{
//动态数组
Array1 a = new Array1(10);
for (int i = 0; i < 10; i++)
{
a.AddLast(i);
}
Console.WriteLine(a);
a.AddLast(66);
Console.WriteLine("末尾添加元素");
Console.WriteLine(a);
a.Add(2, 77);
Console.WriteLine("在索引2添加元素");
Console.WriteLine(a);
Console.WriteLine("获取头部元素"+a.GetFirst());
Console.WriteLine("获取尾部元素"+a.GetLast());
Console.WriteLine("获取索引1的元素"+a.Get(1));
a.Set(1, 1000);
Console.WriteLine("修改索引1的元素");
Console.WriteLine(a);
a.RemoveAt(2);
Console.WriteLine("删除索引2的元素");
Console.WriteLine(a);
a.Remove(4);
Console.WriteLine("删除数据元素4");
Console.WriteLine(a);
Console.Read();
}
}
}
1.3 装箱和拆箱
装箱:值类型转换为引用类型
拆箱:引用类型转换为值类型
namespace DataStructure
{
class Program
{
static void Main(string[] args)
{
int n = 10000000;
Stopwatch t1 = new Stopwatch();//计时器
Stopwatch t2 = new Stopwatch();
Stopwatch t3 = new Stopwatch();
Stopwatch t4 = new Stopwatch();
Console.WriteLine("测试值类型对象int");
t1.Start();
List<int> l = new List<int>();
for (int i = 0; i < n; i++)
{
l.Add(i);//不发生装箱
int x = l[i];//不发生拆箱
}
t1.Stop();
Console.WriteLine("List'time: " + t1.ElapsedMilliseconds + "ms");
t2.Start();
ArrayList a = new ArrayList();
for (int i = 0; i < n; i++)
{
a.Add(i);//发生装箱,提供object实参,int类型转换为引用类型
int x = (int)a[i];//发生拆箱,object转int,引用类型转换为值类型
}
t2.Stop();
Console.WriteLine("ArrayList'time: " + t2.ElapsedMilliseconds + "ms");
//频繁装箱拆箱影响性能
Console.WriteLine("测试引用类型对象string");
t3.Start();
List<string> l2 = new List<string>();
for (int i = 0; i < n; i++)
{
l2.Add("x");//不发生装箱
string x = l2[i];//不发生拆箱
}
t3.Stop();
Console.WriteLine("List'time: " + t3.ElapsedMilliseconds + "ms");
t4.Start();
ArrayList a2 = new ArrayList();
for (int i = 0; i < n; i++)
{
a2.Add("X");//不发生装箱
string x = (string)a2[i];//不发生拆箱,这里是object转换为string,同为引用类型
}
t4.Stop();
Console.WriteLine("ArrayList'time: " + t4.ElapsedMilliseconds + "ms");
Console.Read();
}
}
}
发生了拆箱装箱,运行时间较长,频繁装箱拆箱会影响性能。
1.4 泛型和非泛型
存储任意类型数据可以使用ArrayList,但是存储int类型 会频繁装箱拆箱,这时候我们可以使用泛型List
泛型数组List有两个优点:
-
对于存储值类型数据,性能更优
-
使代码清晰和保证类型安全
List l=new List();
使用泛型实现动态数组,在上面原有Array1类修改
using System;
using System.Collections.Generic;
using System.Text;
namespace DataStructure
{
class Array2<T>//编写动态数组框架
{
private T[] data;//存储元素的静态数组data
private int N;//存储元素个数N
public Array2(int capacity)//有参构造
{
data = new T[capacity];
N = 0;
}
public Array2() : this(10) { }//无参构造
//public Array1()
//{
// data = new int[10];
// N = 0;
//}
private void ResetCapacity(int newCapacity)
{
T[] newData = new T[newCapacity];
for (int i = 0; i < N; i++)
newData[i] = data[i];
data = newData;
}
public int Capacity//获取数组容量
{
get { return data.Length; }
}
public int Count//获取数组元素个数
{
get { return N; }
}
public bool IsEmpty//判断数组是否为空
{
get { return N == 0; }
}
public void Add(int index, T e)//添加元素到数组中的指定索引位置
{
if (index < 0 || index > N)//判断索引位置是否合法
throw new ArgumentException("数组索引越界");
if (N == data.Length)//判断数组容量是否满了
ResetCapacity(2 * data.Length);
for (int i = N - 1; i >= index; i--)//从数组末尾向后移动元素
data[i + 1] = data[i];
data[index] = e;
N++;
}
public void AddLast(T e)//数组末尾添加元素
{
Add(N, e);
}
public void AddFirst(T e)//数组头部添加元素
{
Add(0, e);
}
public T Get(int index)//获取指定索引位置元素
{
if (index < 0 || index >= N)
throw new ArgumentException("数组索引越界");
return data[index];
}
public T GetFirst()//获取首个元素
{
return Get(0);
}
public T GetLast()//获取末尾元素
{
return Get(N - 1);
}
public void Set(int index, T newE)//修改指定索引的元素
{
if (index < 0 || index >= N)
throw new ArgumentException("数组索引越界");
data[index] = newE;
}
public bool Contains(T e)//是否包含元素
{
for (int i = 0; i < N; i++)
{
if (data[i].Equals(e))
return true;
}
return false;
}
public int IndexOf(T e)//搜索元素的索引
{
for (int i = 0; i < N; i++)
{
if (data[i].Equals(e))
return i;
}
return -1;
}
public T RemoveAt(int index)//删除指定索引的元素
{
if (index < 0 || index >= N)
throw new ArgumentException("索引超出了数组界限");
T del = data[index];
for (int i = index + 1; i <= N - 1; i++)
data[i - 1] = data[i];
N--;
data[N] = default(T);
if (N == data.Length / 4)
ResetCapacity(data.Length / 2);
return del;
}
public T RemoveFirst()
{
return RemoveAt(0);
}
public T RemoveLast()
{
return RemoveAt(N - 1);
}
public void Remove(T e)//删除指定元素
{
int index = IndexOf(e);
if (index != -1)
RemoveAt(index);
}
public override string ToString()//打印数组
{
StringBuilder res = new StringBuilder();
res.Append(string.Format("Array1: count={0} capacity={1}\n", N, data.Length));
res.Append("[");
for (int i = 0; i < N; i++)
{
res.Append(data[i]);
if (i != N - 1)
res.Append(", ");
}
res.Append("]");
return res.ToString();
}
}
}
Main调用
namespace DataStructure
{
class Program
{
static void Main(string[] args)
{
int[] n = { 1, 2, 3, 4, 5, 6, 7, 8 };
Array2<int> a = new Array2<int>();
for (int i = 0; i < n.Length; i++)
a.AddLast(n[i]);
Console.WriteLine(a);
string[] s = { "a", "b", "c", "d" };
Array2<string> a2 = new Array2<string>();
for (int i = 0; i < s.Length; i++)
a2.AddLast(s[i]);
Console.WriteLine(a2);
Console.Read();
}
}