C#面向对象_7_集合
Posted yigegaozhongsheng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#面向对象_7_集合相关的知识,希望对你有一定的参考价值。
集合
复习foreach
string[] strArr = new string[] { "小白", "小黑", "小黄", "小红", "小强" }; foreach (string s in strArr) Console.WriteLine(s);
集合
在C#中,集合和数组都可以用存储多个数据元素,但是集合比数组更加灵活,比如:集合可以动态的添加和删除其中的元素。但数组要实现这一点就非常的麻烦和死板了。
集合的种类
ArrayList动态数组、stcak堆栈、queue队列、sortList排序列表、HashTable哈希表
堆栈
堆栈它是一个存储数据的容器,我们可以想像这个容器就像一个弹夹或瓶子,最先放入的数据在最底下,最后放入的数据在最上面。也就是:“先入后出,后入先出”。
堆栈本质是stack类,向堆栈中加一个数据叫做入栈,取出一个数据叫出栈。
语法定义
Stack 堆栈名 = new Stack();
Stack的常用属性
Count: 所包含的元素个数
Stack的常用方法
clear(): 清除集合中的所有元素
Contains(object obj): 判断某个元素是否包含在当前集合中
Peek(): 返回堆栈最上面的一个元素,但是该元素仍然处于原位置,不会被移除。
pop(): 返回堆栈最上面的一个元素,并且 在堆栈中移除该元素,就好像是将它取出一样。
push(): 向堆栈最上面添加一个元素。
toArray(): 将集合转换为一个数组,并返回这个数组。
快速引用命名空间的小技巧
堆栈位于命名空间 System.Collections,我们可以按如下方法添加该命名空间:
先写入完整的类名(注意大小写)
在类名上右击à解析à选择相应的命名空间
仅限于.net系统框架自带的内置的类和命名空间。
堆栈示例:
//定义堆栈 Stack st = new Stack(); //向堆栈之中添加元素 //堆栈中的所有元素都会自动转换为object类型,也就是说Stack可以存放任意类型的数据,而不像数组一样必须要求类型一致。 st.Push(‘A‘); st.Push(‘B‘); st.Push(‘C‘); st.Push(‘D‘); st.Push(‘E‘); foreach (char c in st) //遍历 Console.WriteLine(c); st.Push(‘F‘); st.Push(‘G‘); //peek()不会移除元素 Console.WriteLine("peek下一个元素是{0}", st.Peek()); Console.WriteLine("peek下一个元素是{0}", st.Peek()); //pop()会移除最上面的元素 Console.WriteLine("pop下一个元素是{0}", st.Pop()); Console.WriteLine("pop下一个元素是{0}", st.Pop()); Console.WriteLine("pop下一个元素是{0}", st.Pop());
队列queue
也是存放数据的容器,就像去超市付款的时候排列一样,先入先出,后入后出。
队列的本质是Queue类,向队列中加入一条数据叫做入队,取出一条数据叫出队。
语法定义
Queue 队列名 = new Queue();
Queue的常用属性
Count: 所包含的元素个数
Queue的常用方法
clear(): 清除集合中的所有元素
Contains(object obj): 判断某个元素是否包含在当前集合中
toArray(): 将集合转换为一个数组,并返回这个数组。
Dequeue(): 出队,返回队列最前面的一个元素,并且在队列中移除该元素,就好像是将它取出来一样。
Enqueue(): 入队,在队列最后添加一个元素。
TrimToSize: 设置队列的实际容量个数。
Queue示例:
//定义队列 Queue q = new Queue(); q.Enqueue(‘A‘); q.Enqueue(‘B‘); q.Enqueue(67); q.Enqueue(68); Console.WriteLine("当前队列为:"); foreach (object a in q) Console.WriteLine(a.ToString()); q.Enqueue(‘E‘); q.Enqueue(‘F‘); Console.WriteLine("添加两个元素之后的队列为:"); foreach (object a in q) Console.WriteLine(a.ToString()); Console.WriteLine("{0}已经出队", q.Dequeue()); Console.WriteLine("{0}已经出队", q.Dequeue()); Console.WriteLine("{0}已经出队", q.Dequeue()); foreach (object a in q) Console.WriteLine(a.ToString());
小技巧
在VS中按F12,就可以跳转到当前光标所在位置的变量、类、对象、方法、接口等等元素的被定义的代码处。
ICollection和IEnumerable接口
所有集合都继承并实现了这两个接口
IEnumerable接口:只要继承了该接口,就必须实现GetEnumerator()方法以便能够被循环遍历访问。
ICollection接口:包含Count等多个方法,子类必须能够实现统计元素个数的功能。
ArrayList
也称为动态数组,它可以用来替代数组,而且它比数组更加灵活,它允许动态的对数组元素进行添加、删除、排序、搜索等操作。
它和数组一样,都为元素分配了下标,而且下标会根据数据元素的改变而自动重新分配。
ArrayList的常用属性
属性 |
描述 |
Capacity |
获取或设置ArrayList可包含的元素个数 |
Count |
ArrayList中实际包含的元素个数 |
IsReadOney |
表示ArrayList是否只读 |
Item |
获取可设置指定索引的元素的值,就是根据下标来得到数据元素。 |
IsFixedSize |
表示ArrayList的容量是否固定 |
ArrayList的常用方法
方法 |
描述 |
int Add(object value) |
在ArrayList的未尾添加一个元素。(该元素会自动被转换为object类型) |
void AddRange(ICollection c ) |
在ArrayList的未尾添加另一个集合(实现了ICollection接口)中的所有元素。 |
void clear() |
移除集合中的所有元素,清空 |
bool Contains(object value) |
判断一个元素是否包含在ArrayList中 |
ArrayList GetRange(int index,int count) |
从当前ArrayList中返回一个子集,包含了从下标index开始的count个元素。 |
int Indexof(object) |
返回某个值在ArrayList中第一次出现的索引(下标),实际上就是搜索一个元素。 |
void insert(int index,object value) |
在ArrayList的指定索引下标位置,插入一个集合中的所有元素。 |
void Remove(object obj) |
根据元素的值来删除第一个匹配的元素 |
void RemoveAt(int index) |
根据下标来删除元素 |
void RemoveRange(int index,int count) |
删除ArrayList中指定范围的元素,从下标index开始的count个元素。 |
void Reverse() |
逆转ArrayList中元素的顺序 |
void SetRange(int index,ICollection c) |
复制某个集合(实现了ICollection接口的集合)到ArrayList指定的下标之后 |
void Sort() |
对ArrayList中的元素进行排序 |
void TrimToSize() |
设置ArrayList中的元素的个数 |
示例:
// ArrayList也是类,因此在使用它之前我们必须要实例化对象: ArrayList al = new ArrayList(); //使用Add方法可以添加数据元素 al.Add(1); al.Add(8); //所有数据都会被自动"装箱" //al.Add("tom"); //al.Add(false); al.Add(9); al.Add(4); al.Add(0); al.Add(6); Console.WriteLine("arrayList容量是:" + al.Capacity); Console.WriteLine("arrayList元素个数是:" + al.Count); //遍历 foreach (int i in al) Console.Write(i + " "); al.Reverse(); Console.WriteLine(); Console.WriteLine("颠倒ArrayList中的元素次序"); foreach (int i in al) Console.Write(i + " "); al.Sort(); Console.WriteLine(); Console.WriteLine("arrayList排序"); foreach (int i in al) Console.Write(i + " "); al.Insert(2, 100); //在下标为2的位置插入100 al.RemoveAt(3); //删除下标为3的数值开始。 Console.WriteLine(); Console.WriteLine("遍历时显示下标和元素值"); for (int i = 0; i < al.Count; i++) Console.WriteLine("下标:{0}值为:{1}", i, al[i]); if (al.Contains(100)) Console.WriteLine("其中包含100");
小练习:
定义一个student类,该类包含属性 姓名、年龄、性别、电话,并具备一个构造 函数来为这四个属性赋值。然后定义一个arrayList,在arrayList中存放5个student对象,遍历显示出这5个学生的信息。最后,删除第三个学生信息。
哈希表
HashTable,其特点是以键值对的方式来存取集合元素。
键key和值value组成一个键值对,使用add()方法来添加。
键名不能重复,键值可以重复。
HashTable的属性
属性 |
描述 |
Count |
HashTable中实际包含的元素个数 |
IsReadOney |
表示HashTable是否只读 |
Item |
获取可设置指定键的元素的值。 |
IsFixedSize |
表示HashTable的容量是否固定 |
Keys |
获取一个ICollection接口的集合,其中包含了Hashtable中的所有键。 |
Values |
获取一个ICollection接口的集合,其中包含了Hashtable中的所有值。 |
HashTable的常用方法
方法 |
描述 |
int Add(object key , object value) |
在HashTable中添加一个带有键名和键值的元素。 |
void clear() |
移除集合中的所有元素,清空 |
bool Contains(object value) |
判断一个元素是否包含在ArrayList中 |
void Remove(object key) |
根据元素的键名来删除第一个匹配的元素 |
bool ContainsKey(object Key) |
判断某个键名是否包含在Hashtable中 |
bool ContainsValue(object value) |
判断某个元素的值是否包含在Hashtable中 |
示例1:
Hashtable ht = new Hashtable(); ht.Add("张三", 98.5f); ht.Add("李四", 81f); ht.Add("王五", 79f); ht.Add("赵六", 89f); ht.Add("沈七", 65f); if (ht.ContainsKey("赵六")) Console.WriteLine("赵六是我班同学,他的成绩是" + ht["赵六"]); Console.WriteLine("遍历哈希表"); /*获取键名的集合:实现了ICollection接口的, * 用于存放所有键名的集合*/ ICollection keys = ht.Keys; foreach (string k in keys) Console.WriteLine("{0}是我班同学,他的成绩是{1}", k, ht[k]);
示例2利用DictionaryEntry类
Hashtable ht = new Hashtable(); ht.Add("张三", 98.5f); ht.Add("李四", 81f); ht.Add("王五", 79f); ht.Add("赵六", 89f); ht.Add("沈七", 65f); //DictionaryEntry类的实例对象,就代表hashTable中的一个键值对 foreach (DictionaryEntry item in ht) Console.WriteLine(item.Key + "的成绩是" + item.Value); 示例3利用枚举器来遍历 Hashtable ht = new Hashtable(); ht.Add("张三", 98.5f); ht.Add("李四", 81f); ht.Add("王五", 79f); ht.Add("赵六", 89f); ht.Add("沈七", 65f); IDictionaryEnumerator IDE = ht.GetEnumerator(); while (IDE.MoveNext()) { Console.WriteLine(IDE.Key + "的成绩是" + IDE.Value); }
SortedList排序列表
它可以看作是hashTable和ArrayList的组合,因为SortedList既可以通过键值对的方式来访问,也可以通过类似数组下标的方式来访问。
SortedList的属性
属性 |
描述 |
Capacity |
获取或设置SortedList可包含的元素个数 |
Count |
SortedList中实际包含的元素个数 |
IsReadOney |
表示SortedList是否只读 |
Item |
获取可设置指定键的元素的值。 |
IsFixedSize |
表示SortedList的容量是否固定 |
Keys |
获取一个ICollection接口的集合,其中包含了SortedList中的所有键。 |
Values |
获取一个ICollection接口的集合,其中包含了SortedList中的所有值。 |
SortedList的方法
方法 |
描述 |
int Add(object key , object value) |
在SortedList中添加一个带有键名和键值的元素。 |
void clear() |
移除集合中的所有元素,清空 |
bool ContainsKey(object Key) |
判断某个键名是否包含在Hashtable中 |
bool ContainsValue(object value) |
判断某个元素的值是否包含在Hashtable中 |
void Remove(object key) |
根据元素的键名来删除第一个匹配的元素 |
void RemoveAt(int index) |
根据下标来删除元素 |
int IndexOfKey(object key) |
返回SotredList中指定键名的那个元素的下标序号。(下标从零开始) |
int IndexOfValue(object value) |
返回SotredList中指定键值第一次出现的那个元素的下标序号 |
IList GetKeyList() |
获取SortedList中的键名的集合 |
IList GetValueList() |
获取SortedList中的键值的集合 |
GetKey(i) |
根据下标返回键名 |
示例:
SortedList sl = new SortedList(); sl.Add("张三", 98.5f); sl.Add("李四", 81f); sl.Add("王五", 79f); sl.Add("赵六", 89f); sl.Add("沈七", 65f); foreach (DictionaryEntry item in sl) { Console.WriteLine(item.Key + "的下标是" + sl.IndexOfKey(item.Key) + "的成绩是" + item.Value); } //我们可以看到,SortedList会根据键名的字符顺序来对元素进行排序 //通过下标来遍历元素的键和值 for (int i = 0; i < sl.Count; i++) { Console.WriteLine(sl.GetKey(i) + "的成绩" + sl.GetValueList()[i]); }
小练习
练习每种集合,ArrayList、Stack、Queue、HashTable、SortedList的创建、添加元素、获取单个元素及遍历操作。
创建一个工具类Tool
在类中添加Name字段,并重写object类的ToString()方法,返回如下格式的字符串,“我是一个”+name+”,我能做XXX”事情。
创建一个尺子类Rule,继承自Tool类,为该类添加构造函数(给name字段赋值),重写ToString()方法,返回格式与父类相似的字符串:“我是一个”+name+”,我能量长度”。
在main主函数中,分别实例化三个工具类和尺子类,并将这些对象放入集合(每种集合都要测试),然后遍历显示出来。
泛型集合
非泛型集合:所有的数据存入集合之后,都会自动的进行装箱操作,转换成object类型。
泛型集合:会声明所存入数据的类型,也就是一个泛型集合中只能存入指定类型的数据。
泛型集合与非泛型集合的对应关系 |
|
泛型集合 |
非泛型集合 |
命名空间: System.Collections.Gengeric |
命名空间: System.Collections |
List<数据类型> |
ArrayList |
Dictionary<数据类型, 数据类型> |
HashTable |
Queue<数据类型> |
Queue |
Stack<数据类型> |
Stack |
SortedList<数据类型,数据类型> |
SortedList |
泛型集合LIst
类似于ArrayList,不同之处是它指定了元素的类型。
语法:
List<数据类型> 集合名 = new List<数据类型>();
List<>与ArrayList的属性、方法几乎是一致的。
示例1:
List<int> ListInt = new List<int>(); ListInt.Add(14); ListInt.Add(28); ListInt.Add(50); foreach (int item in ListInt) Console.WriteLine(item);
示例2:
class student { public student(string sName, int age) { this.sName = sName; this.age = age; } public string sName; public int age; } static void Main(string[] args) { List<student> arrL = new List<student>(); arrL.Add(new student("张三", 18)); arrL.Add(new student("李四", 19)); arrL.Add(new student("王五", 20)); arrL.Add(new student("赵六", 21)); arrL[1].age = 88; //用下标访问并修改元素 arrL.RemoveAt(2); //删除元素 foreach (student item in arrL) Console.WriteLine("学生{0}的年龄是{1}", item.sName, item.age); }
字典Dictionary
类似于HashTable,不同之处是它指定了键名与键值的类型。
语法:
Dictionary<键名类型, 键值类型> 集合名 = new Dictionary<键名类型, 键值类型>();
Dictionary <>与HashTable的属性、方法几乎是一致的。
示例:
Dictionary<string, student> sList = new Dictionary<string, student>(); sList.Add("小白", new student("小白", 15)); sList.Add("小黑", new student("小黑", 16)); sList.Add("小黄", new student("小黄", 17)); sList.Add("小红", new student("小红", 18)); sList.Add("小强", new student("小强", 19)); ICollection keys = sList.Keys; //键名的集合 foreach (string kName in keys) Console.WriteLine("学生姓名{0}学生年龄{1}",sList[kName].sName ,sList[kName].age);
小练习:
自行尝试并总结 队列、堆栈、排序列表的泛型版本集合的添加、遍历、修改、删除等操作,并且自行总结笔记。
将泛型集合List<>当做类似数据库一样的数据源,制作一个学生管理系统。程序启动之后,始终会弹出一个菜单,输入1:查询遍历所有学生。输入2:添加新学生。输入3:修改指定下标的学生的信息。输入4:删除指定下标的学生。学生包含(姓名、年龄、班级、地址)。
linkedList链表集合
它最大的特点是,链表中的每一个元素都好像是一个节点,每个节点存在一个节点属性以指向另一个节点。
语法
LinkedList<数据类型> 集合名 = new LinkedList<数据类型>();
示例:
LinkedList<string> LList = new LinkedList<string>(); LList.AddFirst("张三"); //添加到集合的最前面 LList.AddFirst("李四"); LList.AddLast("王五"); LList.AddLast("李连连"); //添加到集合的最后面 foreach (string s in LList) { Console.WriteLine(s); } //得到最后一个节点 LinkedListNode<string> lastString = LList.Last; Console.WriteLine("最后一个节点是:" + lastString.Value); Console.WriteLine("第一个节点是:" + LList.First.Value); //Next属性指向下一个节点,这就是链表的特点。 Console.WriteLine("第一个节点的后面一个是" + LList.First.Next.Value); Console.WriteLine("第一个节点的后面的后面是" + LList.First.Next.Next.Value); Console.WriteLine("最后节点的前一个是" + LList.Last.Previous.Value); //按索引来查找 Console.WriteLine(LList.ElementAt<string>(1));
说明:
LinkedList<T>它是一个双向链表,它的元素指向前一个与后一个元素。
链表的优点是:如果要插入一个元素到链表之中,性能会非常快。因为你插入元素的时候,只需要修改上一个元素的Next属性和下一个元素的Previous元素的引用就可以了。(而ArrayList则需要重新排列后面所有的元素 )。
链表缺点是查询定位链表中间的元素中,需要较长时间。
LinkedListNode<T>节点
它表示链表中的一个节点元素,可以用来获得元素的上一个与下一个元素的引用 。
LinkedList常用属性与方法
Count 返回链表中的元素个数
First 链表中的第一个节点
Last 链表中的最后一个节点
AddFirst() 向链表的最前面添加一个元素
AddAfter() 向链表的指定元素之后添加一个元素
AddBefore() 向链表的指定元素之前添加一个元素
AddLast() 向链表的最后面添加一个元素
Remove()、RemoveFirst()、RemoveLast() 删除指定的匹配元素,或第一个、最后一个元素
Clear() 清除所有元素
Contains() 搜索一个元素是否包含在集合之中,返回true或false
Find() 搜索一个元素是否包含在集合之中,返回元素的节点类
FindLast() 同上,区别在于它是从后向前查询
创建自己的集合类
在C#中的很多类我们都可以用继承的方式来扩展它
实现自定义非泛型集合类
class Program { static void Main(string[] args) { stdCollections stList = new stdCollections(); stList.add(new student("张三", 18)); stList.add(new student("李四", 19)); Console.WriteLine(stList[0].name); Console.WriteLine(stList[1].name); } } class student { public student(string name, int age) { this.name = name; this.age = age; } public string name; public int age; } class stdCollections : System.Collections.CollectionBase { //添加Add方法实现元素添加功能 public void add(student std) { List.Add(std); } public student this[int index] { get { return (student)List[index]; } set { List[index] = value; } } }
以上是关于C#面向对象_7_集合的主要内容,如果未能解决你的问题,请参考以下文章