数组和集合
数组是最为常见的一种数据结构,是相同类型的、用一个标识符封装到一起的基本类型数据序列或对象序列。可以用一个统一的数组名和下表来唯一确定数组中的元素。实质上数组是一个简单的线性序列,因此数组访问起来很快。而集合可以看成是一种特殊的数组,他也可以存储多个数据,C#中长常用的集合包括ArrayList集合和Hashtable(哈希表)。
1 数组概述
数组是大部分编程语言中都支持的一种数据类型,无论是C语言、C++、C#还是Java,都支持数组的概念。
数组是具有相同数据类型的一组数据的集合。在程序设计中,可以将这些集合称为数组。数组中的每一个变量称为数组的元素,数组能够容纳元素的数量称为数组的长度。数组中的每个元素都具有唯一的索引与其相对应,数组的索引从零开始。
数组是通过指定数组的元素类型、数组的秩(维数)及数组每个维度的上线和下限来定义的,及一个数组的定义需要包含一下几个要素。
元素类型
数组的维数
每个维数的上下限
在程序设计中引入数组可以更有效的管理和处理数据。可根据数组的维数将数组分为一维数组、二维数组…
2 一维数组的创建和使用
一维数组实质上是一组相同数据类型的线性集合,当在程序中需要处理一维数组时,或传递一组数据时,可以应用这种类型的数组。
2.1 一维数组的创建
数组作为对象允许使用关键字new进行内存分配。在使用数组之前,必须首先定义数组变量所属的类型。一维数组的创建形式有俩种。
1.先声明,再用new运算符进行内存分配(元素初始值为0)
int arr[]; // 数组元素类型[] 数组名;
arr = new int[5] // 数组名字 = new 数组元素类型[数组元素的个数];
2.声明的同时维数组分配内存
int [] month = new int[12]; //数组元素类型[] 数组名 = new 数组元素类型[数组元素的个数]
2.2一维数组的初始化
数组可以与基本数据类型一样进行初始化操作,数组的初始化可以分别初始化数组中的每个元素。
int[] arr = new int []{1,2,3,4,5}
int[] arr2 = {1,2,3,4,5}
2.3 一维数组的使用
实例:
//创建并初始化一维数组
int[] day = new int[] { 1, 2, 3, 4, 5, 6, 7 };
for (int i = 0; i < day.Length; i++)
{
Console.WriteLine("day[i]");
}
Console.ReadKey();
3 二维数组的创建和使用
二维数组常用于标识表,表中的信息以行和列的形式组织,第一个下标代表元素的行,第二个下标代表元素所在的列。
3.1 二维数组的创建
二维数组可以看做是特殊的一维数组
1.先声明,再用new运算符进行内存分配(元素初始值为0)
int[,] myarr; // 数组元素类型[,] 数组名字;
int[,] myarrr = new int[2,4] // 数组名字 = new 数组元素类型[数组元素的个数];
2.声明的同时为数组分配内存
//第一种方式:为每一组内存分配空间
int[,] a = new int[2,4];
//第二种方式:分别为每一组分配内存空间
int[,] a = new int[2,];
a[0] = new int[2];
a[0] = new int[2];
3.2 二维数组的初始化
二维数组的初始化同一维数组相似
int[,] arr = new int [] {{1,2},{4,5}};
int[] arr2 = {{1,2},{4,5}};
3.3 二维数组的使用
实例:
static void Main(string[] args)
{
int[,] arr = new int[2, 2] { { 1, 2 }, { 3, 4 } };
Console.WriteLine("数组的行数:" + arr.GetLength(0));
Console.WriteLine("数组的行数:" + arr.GetLength(1));
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Console.Write(arr[i,j] + " ");
}
Console.WriteLine();
}
Console.ReadLine();
}
4 数组的基本操作
C#中的数组是由System.Array类派生而来的引用对象,因此可以使用Array类中的各种方法对数组进行各种操作。
4.1 遍历数组
遍历数组就是获取数组中的每个元素,C#中可以使用foreach语句实现数组的遍历功能。
实例:
//创建并初始化一维数组
int[] day = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
foreach (var num in day)
{
Console.WriteLine(num);
}
Console.ReadKey();
4.2 添加/删除数组元素
4.2.1添加数组元素
添加数组元素有俩种情况:
- 在数组中添加一个元素
- 在数组中添加一个数组
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 8};
Console.WriteLine("源数组:");
foreach (var num in arr)
{
Console.Write(num + " ");
}
arr = AddArrayYS(arr, 6, 7);
Console.WriteLine();
Console.WriteLine("增加元素后的数组:");
foreach (var num in arr)
{
Console.Write(num + " ");
}
int[] arr2 = new int[] { 9, 10 };
arr = AddArraySZ(arr, arr2, 8);
Console.WriteLine();
Console.WriteLine("增加数组后的数组:");
foreach (var num in arr)
{
Console.Write(num + " ");
}
Console.ReadLine();
}
/// <summary>
/// 一维数组中增加单个元素
/// </summary>
/// <param name="ArrarBron">源数组</param>
/// <param name="Index">添加索引</param>
/// <param name="Value">添加值</param>
/// <returns>添加单个元素后返回的数组</returns>
static int[] AddArrayYS(int[] ArrarBron, int Index, int Value)
{
if (Index >= ArrarBron.Length)
Index = ArrarBron.Length - 1;
int[] TeamArray = new int[ArrarBron.Length + 1];
for (int i = 0; i < TeamArray.Length; i++)
{
if (Index >= 0)
{
if (i < Index + 1)
TeamArray[i] = ArrarBron[i];
else if (i == Index + 1)
TeamArray[i] = Value;
else
TeamArray[i] = ArrarBron[i-1];
}
else
{
if (i == 0)
TeamArray[i] = Value;
else
TeamArray[i] = ArrarBron[i - 1];
}
}
return TeamArray;
}
/// <summary>
/// 一维数组中增加一个一维数组元素
/// </summary>
/// <param name="ArrarBron">源数组</param>
/// <param name="ArrayAdd">添加数组</param>
/// <param name="Index">添加索引</param>
/// <returns>源数组添加数组后得到的数组</returns>
static int[] AddArraySZ(int[] ArrarBron,int[] ArrayAdd, int Index)
{
if (Index >= (ArrarBron.Length))
Index = ArrarBron.Length - 1;
int[] TeamArray = new int[ArrarBron.Length + ArrayAdd.Length];
for (int i = 0; i < TeamArray.Length; i++)
{
if (Index>=0)
{
if (i < (Index + 1))
TeamArray[i] = ArrarBron[i];
else if (i == (Index + 1))
{
for (int j = 0; j < ArrayAdd.Length; j++)
TeamArray[i + j] = ArrayAdd[j];
i = i + ArrayAdd.Length - 1;
}
else
TeamArray[i] = ArrarBron[i - ArrayAdd.Length];
}
else
{
if (i==0)
{
for (int j = 0; j < ArrayAdd.Length; j++)
TeamArray[i + j] = ArrayAdd[j];
i = i + ArrayAdd.Length - 1;
}
else
TeamArray[i] = ArrarBron[i - ArrayAdd.Length];
}
}
return TeamArray;
}
}
}
4.2.2 删除数组元素
删除数组元素有俩种情况
- 在不改变数组元素总数的情况下删除指定元素(也就是删除元后面的元素覆盖要删除的元素)
- 在删除元素后,根据上出元素的个数n,是删除后的数组长度减
n
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 1, 2, 3, 4, 5, 6 };
Console.Write("源数组:");
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i] + " ");
}
DeleteArry(arr, 0, 1);
Console.WriteLine("");
Console.Write("删除元素且不改变其长度:");
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i] + " ");
}
arr = DeleteArry2(arr, 0, 1);
Console.WriteLine("");
Console.Write("删除元素并改变其长度:");
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i] + " ");
}
Console.ReadLine();
}
/// <summary>
/// 删除源数组中的某个元素且不改变源数组长度
/// </summary>
/// <param name="ArrayBorn"></param>
/// <param name="Index"></param>
/// <param name="Len"></param>
static void DeleteArry(int[]ArrayBorn,int Index,int Len)
{
if (Len <= 0)
return;
if (Index == 0 && Len >= ArrayBorn.Length)
Len = ArrayBorn.Length;
else if ( ( Index + Len) >= ArrayBorn.Length )
Len = ArrayBorn.Length - Index - 1;
int i = 0;
for (i = 0; i < ArrayBorn.Length - Index - Len; i++)
ArrayBorn[i + Index] = ArrayBorn[i + Index + Len];
for (int j = (ArrayBorn.Length - 1); j > (ArrayBorn.Length - Len - 1); j--)
ArrayBorn[j] = 0;
}
/// <summary>
/// 删除源数组中的元素且改变数组长度
/// </summary>
/// <param name="ArrayBorn">源数组</param>
/// <param name="Index">删除索引</param>
/// <param name="Len">删除长度</param>
/// <returns>teamArray删除后的数组</returns>
static int[] DeleteArry2(int[] ArrayBorn, int Index, int Len)
{
if (Len <= 0)
return ArrayBorn;
if (Index == 0 && Len >= ArrayBorn.Length)
Len = ArrayBorn.Length;
else if ((Index + Len) >= ArrayBorn.Length)
Len = ArrayBorn.Length - Index - 1;
int[] teamArray = new int[ArrayBorn.Length - Len];
for (int i = 0; i < ArrayBorn.Length - Index - Len; i++)
{
if (i >= Index)
teamArray[i] = ArrayBorn[i + Len];
else
teamArray[i] = ArrayBorn[i];
}
return teamArray;
}
}
}
4.3 对数组进行排序
C#中提供了用于对数组进行排序的方法Array.Sort和Array.Reverse,以上俩方法只针对一维数组。
Array.Sort(arr)
Array.Reverse(arr)
int[] arr = new int[] { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
Array.Sort(arr);
Console.WriteLine("排序后的数组arr");
foreach (var num in arr)
{
Console.Write(num + " ");
}
Array.Reverse(arr);
Console.WriteLine();
Console.WriteLine("反转后的数组arr");
foreach (var num in arr)
{
Console.Write(num + " ");
}
Console.ReadLine();
4.4 数组的合并与拆分
在对数组进行拆分或合并时,应保证数组与数组之间的类型一致。
4.4.1 数组的合并
数组的合并实际上就是将多个一维数组合并成一个个一维数组,过着将多个一维数组合并称为一个二维数组或多维数组。
在合并数组时,如果是将俩个一维数组合并成一个一维数组,那么新生成数组的元素个数等于要合并的俩个数组的元素个数和。
例:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] arr1 = new int[] { 1, 2, 3, 4, 5 };
int[] arr2 = new int[] { 6, 7, 8, 9, 10 };
int[] arr3 = new int[arr1.Length + arr2.Length];
for (int i = 0; i < arr3.Length; i++)
{
if (i < arr1.Length)
arr3[i] = arr1[i];
else
arr3[i] = arr2[i - arr1.Length];
}
Console.WriteLine("合并后的一维数组:");
foreach (var num in arr3)
{
Console.Write(num + " ");
}
int[,] arr4 = new int[2,5];
for (int i = 0; i < arr4.Rank; i++)
{
switch (i) {
case 0:
{
for (int j = 0; j < arr1.Length; j++)
arr4[i,j] = arr1[j];
break;
}
case 1:
{
for (int j = 0; j < arr2.Length; j++)
arr4[i, j] = arr2[j];
break;
}
}
}
Console.WriteLine();
Console.WriteLine("合并后的二维数组:");
for (int i = 0; i < arr4.Rank; i++)
{
for (int j = 0; j <= arr4.GetUpperBound(arr4.Rank - 1 ) ; j++)
{
Console.Write(arr4[i, j] + " ");
}
Console.WriteLine();
}
Console.ReadLine();
}
}
}
4.4.2 数组的拆分
数组的拆分实际上就是将一个一维数组拆分成多个一维数组,或是将多维数组分成多个一维数组或多个多维数组。
例:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[,] arr1 = new int[2, 3] {{ 1, 2, 3 },{ 2, 4, 5 } };
int[] arr2 = new int[3] ;
int[] arr3 = new int[3];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
switch (i)
{
case 0:arr2[j] = arr1[i, j];break;
case 1:arr3[j] = arr1[i, j]; break;
}
}
}
Console.WriteLine();
Console.WriteLine("数组一");
foreach (var num in arr2)
{
Console.Write(num + " ");
}
Console.WriteLine();
Console.WriteLine("数组二");
foreach (var num in arr3)
{
Console.Write(num + " ");
}
Console.ReadLine();
}
}
}
5 数组的排序算法
5.1 冒泡排序
冒泡排序的过程就是小数往前放,大数往后放,类似水中的气泡上升的过程,所以称作冒泡排序。
- 基本思想
冒泡排序的基本思想是对比相邻的元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把较大的元素移动到数组的后边(交换俩个元素的位置)。 - 算法示例
冒泡排序是由双层循环实现的,其中外层循用于控制循环轮数,一般是要排序的数组长度减1,一维最后一次循环只剩一个数组元素,不需要比对,同时数组已经完成排序。而内层循环主要用于比对数组中相邻元素的大小,以确定是否交换位置,对比和交换次数以排序轮数而减少。 - 算法实现
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
int a, b;
for (int i = 0; i < arr.Length -1 ; i++)
{
a = i + 1;
id:
if (arr[i]>arr[a])
{
b = arr[i];
arr[i] = arr[a];
arr[a] = b;
goto id;
}
else
{
if (a<arr.Length - 1)
{
a++;
goto id;
}
}
}
foreach (var num in arr)
{
Console.Write(num + " ");
}
Console.ReadLine();
}
}
}
5.2 直接插入排序
-
基本思想
直接插入排序是一种最简单的排序方式,其基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表,然后再从剩下的关键字中选取一个插入对象,反复执行直到整个序列有序。 -
算法示例
-
算法实现
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
for (int i = 0; i < arr.Length; i++)
{
int temp = arr[i];
int j = i;
while ((j>0)&&(arr[j-1]>temp))
{
arr[j] = arr[j - 1];
--j;
}
arr[j] = temp;
}
foreach (var num in arr)
{
Console.Write(num + " ");
}
Console.ReadLine();
}
}
}
5.3 选择排序
选择排序方法比冒泡排序略快一些,也时常用的排序算法。
- 基本思想
选择排序的基本思想是将指定排序位置与其他元素分别比对,如果满足条件就交换元素值,注意这里有别于冒泡排序,不是交换相邻元素,而是把满足条件的元素与指定的排序位置交换(例如从第一个元素开始排序),这样排序好的位置逐渐扩大,最后整个数组都成为已排好的格式。
好比从包含数字1~10的乱序的数字堆中分别选择合适的数字,组成一个从1到10的排序,首先从数字堆中选出1放在第一位,在选出2放在第二位,以此类推知道找到数字9放到8的后面。
-
算法示例
-
算法实现
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
int min;
for (int i = 0; i < arr.Length; i++)
{
min = i;
for (int j = i + 1; j < arr.Length; j++)
{
if (arr[j] < arr[min])
min = j;
}
int t = arr[min];
arr[min] = arr[i];
arr[i] = t;
}
foreach (var num in arr)
{
Console.Write(num + " ");
}
Console.ReadLine();
}
}
}
6 ArrayList类
ArrayList类相当于一种高级的动态数组,它是Array类的升级版本。
6.1 ArrayList类概述
ArrayList类位于System.Collections命名空间下,它可以动态的添加和删除元素。可以将ArrayList类看做扩充了功能的数组,但它并不等于数组。
与数组相比,ArrayList类为开发人员提供了一下功能
- 数组的容量是固定的,而ArrayList的容量可以根据需要自动扩充。
- ArrayList提供添加、删除和插入某一范围元素的方法,但在数组中,只能一次获取或设置一个元素的值。
- ArrayList提供将只读和固定大小包装返回到集合的方法,而数组不提供。
- ArrayList只能是一维形式,而数组可以是多维。
ArrayList提供了三个构造器,所以有三种声明方式
ArrayList List1 = new ArrayList(); //创建ArrayList集合
int[] arr = new int[2];
ArrayList List2 = new ArrayList(arr); //将指定的数组添加到ArrayList中
ArrayList List3 = new ArrayList(10); //用指定的大小初始化ArrayList内部的数组
ArrayList常用属性及说明
属性 | 说明 |
---|---|
Capacity | 获取或设置ArrayList可包含的元素数 |
Count | 获取ArrayList中实际包含的元素数 |
IsFixedSize | 获取一个值,该值指示ArrayList是否具有固定大小 |
IsReadOnly | 获取一个值,该值指示ArrayList是否为只读 |
IsSynchronized | 获取一个值,该值指示是否同步对ArrayList的访问 |
Item | 获取或设置指定索引处的元素 |
SyncRoot | 获取可用于同步ArrayList访问的对象 |
6.2 ArrayList元素的添加
ArrayList允许null值作为有效值,并且允许重复的元素。
- Add方法:在ArrayList末尾处添加元素。
- Insert方法:在ArrayLis指定索引处插入元素。
例:
int[] arr = new int[] { 1, 3, 5, 7, 9 };
ArrayList List = new ArrayList(arr);
List.Add(11);
List.Insert(0, 0);
//向集合中插入数组
int[] arr2 = new int[] { 4, 4, 4, 4, 4 };
List.InsertRange(6, arr2);
foreach (var num in List)
{
Console.Write(num + " ");
}
Console.ReadLine();
6.3 ArrayList元素的删除
- Clear方法:将ArrayList中所有元素移出
- Remove方法:从ArrayList中移除特定对象的第一个匹配项
- RemoveAt方法:用来移出ArrayList指定索引处的元素
- RemoveRange方法:用来从ArrayList中移除一定范围的元素
int[] arr = new int[] { 1, 2, 3, 4, 5 ,6, 7, 8, 9, 10 ,1 };
ArrayList List = new ArrayList(arr);
Console.Write("源集合");
foreach (var num in List)
{
Console.Write(num + " ");
}
List.Remove(1); //移除第一个匹配项
Console.WriteLine();
Console.Write(" Remove操作");
foreach (var num in List)
{
Console.Write(num + " ");
}
List.RemoveAt(2); //移除指定索引处元素
Console.WriteLine();
Console.Write(" RemoveAt操作");
foreach (var num in List)
{
Console.Write(num + " ");
}
List.RemoveRange(2,2); //从指定索引处移除指定个数元素
Console.WriteLine();
Console.Write(" RemoveRange");
foreach (var num in List)
{
Console.Write(num + " ");
}
List.Clear(); //清空集合
Console.WriteLine();
Console.Write( " Clear操作");
foreach (var num in List)
{
Console.Write(num + " ");
}
Console.ReadLine();
6.4 ArrayList的遍历
ArrayList集合的遍历与数组相似,都可以使用foreach语句。
例:
int[] arr = new int[] { 1, 2, 3, 4, 5 ,6, 7, 8, 9, 10 ,1 };
ArrayList List = new ArrayList(arr);
foreach (var num in List)
{
Console.Write(num + " ");
}
Console.ReadLine();
6.5 ArrayList元素的查找
查找ArrayList集合中的元素时,可以使用ArrayList类提供的Contains方法、IndexOf方法和LastIndexOf方法。
例:
int[] arr = new int[] { 1, 2, 3, 4, 5 ,6, 7, 8, 9, 10 ,1 };
ArrayList List = new ArrayList(arr);
Console.Write(List.Contains(1)); //true
Console.ReadLine();
7 Hashtable(哈希表)
7.1 Hashtable概述
Hashtable通常称为哈希表,它表示键/值对的集合,这些键/值对根据键的哈希代码进行组织。它的每个元素都是一个存储在DictionEntry对象中的键?值对.键不能为空引用,但值可以。
常用的俩种创建Hashtable方法
Hashtable hs1 = new Hashtable(); //使用默认的初始容量、加载因子、哈希代码提供程序和默认比较器来初始化Hashtable类的新的空实例
Hashtable hs1 = new Hashtable(10); //指定Hashtable对象最初可包含的元素的近似数目。
Hashtable常用属性及说明
属性 | 说明 |
---|---|
Count | 获取包含在Hashtable中的键/值对数目 |
IsFixedSize | 获取一个值,该值指示Hashtable是否具有固定的大小 |
IsReadOnly | 获取一个值,该值指示Hashtable是否为只读 |
IsSynchronized | 获取一个值,该值指示是否同步对Hashtable的访问 |
Item | 获取或设置与指定的键相关联的值 |
Keys | 获取包含Hashtable中的键的ICollation |
SyncRoot | 获取可用于同步Hashtable访问的对象 |
Values | 获取包含Hashtable中的值的ICollation |
7.2 Hashtable元素的添加
- Add方法 : 用来将带有指定键和值的元素添加到ICollation中
语法:
public virtual void Add(Object key,Object value)
--key : 要添加元素的键
--value:要添加元素的值
实例:
Hashtable ht = new Hashtable();
ht.Add("id", "001");
ht.Add("anme", "Tom");
ht.Add("sex", "Boy");
Console.Write(ht.Count); // 获取Hashtable中的元素个数
Console.ReadLine();
7.3 Hashtable元素的删除
- Clear方法 :用来移除HashTable中所有元素
- Remove方法:用来移除HashTable中带有指定键的元素
语法:
public virtual void Clear()
public virtual void Remove(Object key)
--key : 要移除元素的键
实例:
Hashtable ht = new Hashtable();
ht.Add("id", "001");
ht.Add("anme", "Tom");
ht.Add("sex", "Boy");
Console.WriteLine("源集合元素个数" + ht.Count);
ht.Remove("id");
Console.WriteLine("移出某对元素后的个数" + ht.Count);
ht.Clear();
Console.WriteLine("清空集合后的元素个数" + ht.Count);
Console.ReadLine();
7.4 Hashtable的遍历
HashTable的遍历与数组相似可以使用foreach语句,由于HashTable中的元素是键值对,因此需要使用DictionaryEntry结构来进行遍历,DictionaryEntry结构标识一个键值对的集合。
Hashtable ht = new Hashtable();
ht.Add("id", "001");
ht.Add("anme", "Tom");
ht.Add("sex", "Boy");
foreach (DictionaryEntry dicEntry in ht)
{
Console.WriteLine("\t" + dicEntry.Key + "\t" +dicEntry.Value);
}
Console.ReadLine();
7.5 Hashtable元素的查找
- Contain方法:用来确定HashTable中是否包含特定的键
- ContainKey方法:用来确定HashTable中是否包含特定的键
- ContainValue方法:用来确定HashTable中是否包含特定的值
语法:
public virtual bool Contains(Object key)
--key:要在哈希表中定位的键
--返回值:包含有指定键的元素则为True,否则False
public virtual bool ContainsValue(Object value)
--value:要在哈希表中定位的值,该值可以为空引用
--返回值:包含有指定value的元素则为True,否则False
实例:
Hashtable ht = new Hashtable();
ht.Add("id", "001");
ht.Add("anme", "Tom");
ht.Add("sex", "Boy");
Console.WriteLine(ht.Contains("id"));
Console.WriteLine(ht.ContainsValue("001"));