一、c#中的数组、ArrayList、List区别
在C#中数组,ArrayList,List都能够存储一组对象,那么这三者到底有什么样的区别呢。
- (1)数组引入的命名空间:using System;
- (2)Array:用法基本与数组同,引入命名空间:using System;
- (3)ArrayList:引入命名空间: using System.Collections
- (4)List:引入命名空间:using System.Collections.Generic;
1.数组
数组在C#中最早出现的。在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单。
//string[] s= {"a","b"};
string[] s=new string[2];
//赋值
s[0]="a";
s[1]="b";
//修改
s[1]="a1";
但是数组存在一些不足的地方。在数组的两个数据间插入数据是很麻烦的,而且在声明数组的时候必须指定数组的长度,数组的长度过长,会造成内存浪费,过段会造成数据溢出的错误。如果在声明数组时我们不清楚数组的长度,就会变得很麻烦。针对数组的这些缺点,C#中最先提供了ArrayList对象来克服这些缺点。
2.ArrayList
ArrayList是命名空间System.Collections下的一部分,在使用该类时必须进行引用,同时继承了IList接口,提供了数据存储和检索。ArrayList对象的大小是按照其中存储的数据来动态扩充与收缩的。所以,在声明ArrayList对象时并不需要指定它的长度。
ArrayList list1 = new ArrayList();
//新增数据
list1.Add("cde");
list1.Add(5678);
//修改数据
list[2] = 34;
//移除数据
list.RemoveAt(0);
//插入数据
list.Insert(0, "qwe");
从上面例子看,ArrayList好像是解决了数组中所有的缺点,为什么又会有List?
我们从上面的例子看,在List中,我们不仅插入了字符串cde,而且插入了数字5678。这样在ArrayList中插入不同类型的数据是允许的。因为ArrayList会把所有插入其中的数据当作为object类型来处理,在我们使用ArrayList处理数据时,很可能会报类型不匹配的错误,也就是ArrayList不是类型安全的。在存储或检索值类型时通常发生装箱和取消装箱操作,带来很大的性能耗损。
装箱与拆箱的概念:
装箱:就是将值类型的数据打包到引用类型的实例中 比如将string类型的值abc赋给object对象obj
String i=”abc”;
object obj=(object)i;
拆箱:就是从引用数据中提取值类型:比如将object对象obj的值赋给int类型的变量j
object obj=”abc”;
int j = (int)obj;//拆箱:将引用类型的obj转化为值类型j;
补充:
Array的用法与数组几乎一样,可以看做是数组。在定义的时候需要指定长度;ArrayList的用法与普通集合一样,定义的时候不需要指定长度;如:
Array[] animalArray = new Array[2];
ArrayList animalArrayList = new ArrayList();
3.泛型List
因为ArrayList存在不安全类型与装箱拆箱的缺点,所以出现了泛型的概念。List类是ArrayList类的泛型等效类,它的大部分用法都与ArrayList相似,因为List类也继承了IList接口。最关键的区别在于,在声明List集合时,我们同时需要为其声明List集合内数据的对象类型。
list = new List<string>();
//新增数据
list.Add(“abc”);
//修改数据
list[0] = “def”;
//移除数据
list.RemoveAt(0);
上例中,如果我们往List集合中插入int数组123,IDE就会报错,且不能通过编译。这样就避免了前面讲的类型安全问题与装箱拆箱的性能问题了。
二、C# ArrayList、HashSet、HashTable、List、Dictionary的区别详解
HashTable是一种根据key查找非常快的键值数据结构,不能有重复key,而且由于其特点,其长度总是一个素数,所以扩容后容量会比2倍大一点点,加载因子为0.72f。
当要大量使用key来查找value的时候,HashTable无疑是最有选择,HashTable与ArrayList一样,是非泛型的,value存进去是object,存取会发生装箱、拆箱,所以出现了Dictionary。
Dictionary是HashTable的泛型版本,存取同样快,但是不需要装箱和拆箱了。而且,其优化了算法,Hashtable是0.72,它的浪费容量少了很多。
1.HashTable
using System;
using System.Collections;
namespace CollectionsApplication
{
class Program
{
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
ht.Add("001", "Zara Ali");
ht.Add("002", "Abida Rehman");
ht.Add("003", "Joe Holzner");
ht.Add("004", "Mausam Benazir Nur");
ht.Add("005", "M. Amlan");
ht.Add("006", "M. Arif");
ht.Add("007", "Ritesh Saikia");
if (ht.ContainsValue("Nuha Ali"))
{
Console.WriteLine("This student name is already in the list");
}
else
{
ht.Add("008", "Nuha Ali");
}
// 获取键的集合
ICollection key = ht.Keys;
foreach (string k in key)
{
Console.WriteLine(k + ": " + ht[k]);
}
Console.ReadKey();
}
}
}
001: Zara Ali
002: Abida Rehman
003: Joe Holzner
004: Mausam Benazir Nur
005: M. Amlan
006: M. Arif
007: Ritesh Saikia
008: Nuha Ali
2.Dictionary
//Persion.cs
using System;
namespace SampleList
{
class Person
{
public string name;
public int age;
//构造函数
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
}
}
//CustomDictionary.cs
using System;
using System.Collections.Generic;
namespace SampleList
{
class CustomDictionary
{
//定义一个字典变量
static Dictionary<int, Person> dicPerson = new Dictionary<int, Person>();
public static void LearnDictionaryInfo()
{
//添加键值
Person p1 = new Person("hjc", 22);
Person p2 = new Person("tf", 21);
dicPerson.Add(0, p1); //方式1
dicPerson[1] = p2; //方式2
//取值
Console.WriteLine("\n");
Console.WriteLine("取值 name:" + dicPerson[0].name + "—" + "age:" + dicPerson[0].age);
//改值
Console.WriteLine("\n");
dicPerson[1].age = 20;
Console.WriteLine("改值 name:" + dicPerson[1].name + "—" + "age:" + dicPerson[1].age);
//遍历key
Console.WriteLine("\n");
Console.WriteLine("遍历 key");
foreach (int key in dicPerson.Keys)
{
string id = "用户ID:" + key;
string str = string.Format("name:{0} age:{1}", dicPerson[key].name, dicPerson[key].age);
Console.WriteLine(id + "\t" + str);
}
//遍历value
Console.WriteLine("\n");
Console.WriteLine("遍历 value");
foreach (Person value in dicPerson.Values)
{
string str = string.Format("name:{0} age:{1}", value.name, value.age);
Console.WriteLine(str);
}
//遍历字典
Console.WriteLine("\n");
Console.WriteLine("遍历字典");
foreach (KeyValuePair<int, Person> kvp in dicPerson)
{
string str = string.Format("key:{0}/name:{1}/age:{2}", kvp.Key, kvp.Value.name, kvp.Value.age);
Console.WriteLine(str);
}
// 删除元素
Console.WriteLine("\n");
Console.WriteLine("删除元素");
if (dicPerson.ContainsKey(1)) //如果存在
dicPerson.Remove(1);
foreach (Person value in dicPerson.Values)
{
string str = string.Format("name:{0} age:{1}", value.name, value.age);
Console.WriteLine(str);
}
//清除所有的元素
dicPerson.Clear();
Console.Read();
}
}
}
3.HashSet
HashSet类,算法,存储结构都与哈希表相同,主要是设计用来做高性能集运算的,例如对两个集合求交集、并集、差集等。集合中包含一组不重复出现且无特定顺序的元素。
所谓的HashSet,指的就是 System.Collections.Generic 命名空间下的 HashSet<T> 类,它是一个高性能,无序的集合,因此HashSet它并不能做排序操作,也不能包含任何重复的元素,Hashset 也不能像数组那样使用索引,所以在 HashSet 上你无法使用 for 循环,只能使用 foreach 进行迭代,HashSet 通常用在处理元素的唯一性上有着超高的性能。
HashSet<T> 实现了如下几个接口:
public class HashSet<T> : System.Collections.Generic.ICollection<T>,
System.Collections.Generic.IEnumerable<T>,
System.Collections.Generic.IReadOnlyCollection<T>,
System.Collections.Generic.ISet<T>,
System.Runtime.Serialization.IDeserializationCallback,
System.Runtime.Serialization.ISerializable
{
}
HashSet 只能包含唯一的元素,它的内部结构也为此做了专门的优化,值得注意的是,HashSet 也可以存放单个的 null 值,可以得出这么一个结论:如何你想拥有一个具有唯一值的集合,那么 HashSet 就是你最好的选择,何况它还具有超高的检索性能。
static void Main(string[] args)
{
HashSet<string> hashSet = new HashSet<string>();
hashSet.Add("A");
hashSet.Add("B");
hashSet.Add("C");
hashSet.Add("D");
if (hashSet.Contains("D"))
Console.WriteLine("The required element is available.");
else
Console.WriteLine("The required element isn’t available.");
Console.ReadKey();
}
如果你向 HashSet 中插入重复的元素,它的内部会忽视这次操作而不像别的集合一样抛出异常,接下来展示一下代码:
static void Main(string[] args)
{
HashSet<string> hashSet = new HashSet<string>();
hashSet.Add("A");
hashSet.Add("B");
hashSet.Add("C");
hashSet.Add("D");
hashSet.Add("D");
Console.WriteLine("The number of elements is: {0}", hashSet.Count);//4
Console.ReadKey();
}
4.Queue、Queue
Queue队列,Queue泛型队列,大学都学过,队列,先进先出,很有用。
5.Stack、Stack
Stack堆栈,先进后出。
6.SortedList、SortedList
SortedList集合中的数据是有序的。可以通过key来匹配数据,也可以通过int下标来获取数据。
添加操作比ArrayList,Hashtable略慢;查找、删除操作比ArrayList快,比Hashtable慢。
7.SortedDictionary
SortedDictionary相比于SortedList其性能优化了,SortedList其内部维护的是数组而SortedDictionary内部维护的是红黑树(平衡二叉树)的一种,因此其占用的内存,性能都好于SortedDictionary。唯一差在不能用下标取值。
8.ListDictionary(单向链表),LinkedList(双向链表)
,ArrayList,Hashtable等容器类,其内部维护的是数组Array来,ListDictionary和LinkedList不用Array,而是用链表的形式来保存。链表最大的好处就是节约内存空间。
ListDictionary是单向链表。
LinkedList双向链表。双向链表的优势,可以插入到任意位置。
static void Main(string[] args)
{
LinkedList<int> a = new LinkedList<int>(); //创建一个链表
a.AddFirst(3); //在一开始添加一个节点
a.AddLast(1); //在最后添加一个节点
a.AddLast(4); //在最后添加一个节点
foreach (int i in a)
Console.Write(i + " "); //输出3 1 4
Console.WriteLine();
LinkedListNode<int> cur = a.Find(3); //cur对应3所在的第一个位置
if (cur != null)
{
a.AddAfter(cur, 2); //在3后面添加2
a.AddBefore(cur,5); //在3前面添加5
}
foreach (int i in a)
Console.Write(i + " "); //输出5 3 2 1 4
Console.WriteLine();
Console.WriteLine(cur.Next.Value); //cur当前为3的位置,所以下一个为2
Console.WriteLine(cur.Next.Previous.Value); //3的下一个为2,2的上一个仍然为3
Console.WriteLine(cur.Previous); //Previous为上一个节点
a.RemoveFirst();
foreach (int i in a)
Console.Write(i + " "); //返回3 2 1 4
Console.WriteLine();
a.RemoveLast();
foreach (int i in a)
Console.Write(i + " "); //返回3 2 1
Console.WriteLine();
a.Remove(3); //删除值为3的节点,成功返回true,否则false
a.Clear(); //清空所有的节点
Console.Read();
}
9.HybridDictionary
HybridDictionary的类,充分利用了Hashtable查询效率高和ListDictionary占用内存空间少的优点,内置了Hashtable和ListDictionary两个容器,添加数据时内部逻辑如下:
当数据量小于8时,Hashtable为null,用ListDictionary保存数据。
当数据量大于8时,实例化Hashtable,数据转移到Hashtable中,然后将ListDictionary置为null。
10.BitArray
BitArray这个东东是用于二进制运算,"或"、"非"、"与"、"异或非"等这种操作,只能存true或false;
网友评论