1.5 动态数组
//动态数组
private void ResetCapacity(int newCapacity) //传递一个临时容量
{
int[] newData = new int[newCapacity];
for (int i = 0; i < N; i++)
{
newData[i] = data[i];
}
data = newData;
}
修改Add方法中,空间不足时的情况:
public void Add(int index, int e)
{
if (index < 0 || index > N)
throw new ArgumentException("数组索引越界");
if (N == data.Length)
ResetCapacity(2 * data.Length); //空间不够时进行2倍扩容
for (int i = N - 1; i >= index; i--)
{
data[i + 1] = data[i];
}
data[index] = e;
N++;
}
修改RemoveAt方法中,空间过剩时的情况:
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;
}
测试数组扩容、缩容:
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(33);
Console.WriteLine(a);
for (int i = 0; i < 6; i++)
{
a.RemoveLast();
Console.WriteLine(a);
}
Console.Read();
}
}
1.6 装箱和拆箱
装箱:值类型转换为引用类型
拆箱:引用类型转换为值类型
引用类型:任何称为“类”的类型都是引用类型,使用class修饰
string object
值类型:所有值类型都称为结构或枚举,使用struct或enum修饰
int float double char
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> l1 = new List<int>();
for (int i = 0; i < n; i++)
{
l1.Add(i); //不发生装箱
int x = l1[i]; //不发生拆箱
}
t1.Stop();
Console.WriteLine("List'time: "+t1.ElapsedMilliseconds+"ms");
t2.Start();
ArrayList a1 = new ArrayList();
for (int i = 0; i < n; i++)
{
a1.Add(i); //发生装箱
int x = (int)a1[i]; //发生拆箱
}
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和object都是引用类型
string x = (string)a2[i]; //不发生拆箱
}
t4.Stop();
Console.WriteLine("ArrayList'time: " + t4.ElapsedMilliseconds + "ms");
Console.Read();
}
}
泛型数组List有两个优势:
第一个是对于存储值类型数据,性能更优
第二个是使代码更清晰和保证类型安全
List l = new List();
ArrayList a = new ArrayList();
1.7 使用泛型技术
1.Int[] => object[] ArrayList
2.使用泛型 List
为数组添加泛型功能:
class Array1<E> //表示操作一个未指定的数据类型,E相当于占位符,可为任意字母
//当用户使用这个数组类时,只需要传进去特定的数据类型,这个E就转换成了相应的数据类型
{
private E[] data; //使用E类型的数组
...
public Array1(int capacity)
{
data = new E[capacity]; //开辟E类型的数组空间
...
}
...
public void Add(int index, E e) //添加E类型的元素e
...
public void AddLast(E e)
...
public void AddFirst(E e)
...
public E Get(int index) //返回E类型的变量
...
public E GetFirst()
...
public E GetLast()
...
public void Set(int index,E newE) //将一个元素修改成E类型的值
...
public bool Contains(int e)
{
for (int i = 0; i < N; i++)
{
if (data[i].Equals(e)) //调用.Equals()
//对于泛型,如果传入的是引用类型变量,两个引用类型的变量比较是合法的,它们会比较它们的内存地址。
//但比较的是两个值类型的变量,是非法的,除非这两个值类型的变量都重载了"=="这个操作符。
//这里需要更合适的比较方式————调用.Equals()进行判断是否相等
return true;
}
return false;
}
...
public int IndexOf(int e)
{
...
if (data[i].Equals(e)) //调用.Equals()
...
}
...
public E RemoveAt(int index) //返回E类型的值
{
...
E del = data[index];
...
data[N] = default(E); //E类型的默认值,如果是引用类型赋值成null,如果是值类型赋值成0
...
}
...
public E RemoveFirst()
...
public E RemoveLast()
...
private void ResetCapacity(int newCapacity)
{
E[] newData = new E[newCapacity]; //开辟的是临时的E类型空间
...
}
}
class Program
{
static void Main(string[] args)
{
int[] n = { 1, 2, 3, 4, 5, 6, 7 };
Array1<int> a1 = new Array1<int>();
for (int i = 0; i < n.Length; i++)
a1.AddLast(n[i]);
Console.WriteLine(a1);
string[] s = { "a", "b", "c", "d" };
Array1<string> a2 = new Array1<string>();
for (int i = 0; i < s.Length; i++)
a2.AddLast(s[i]);
Console.WriteLine(a2);
Console.Read();
}
}