文章目录
- 1.简单数据结构类
- (1)动态数组Arraylist
- (2)栈Stack
- (3)队列Queue
- (4)哈希表Hashtable
- 2.泛型
- 3.常用泛型数据结构类
- (1)列表List
- (2)字典Dictionary
- (3)顺序存储和链式存储
- (4)泛型双向链表Linkedlist
- (5)泛型栈和队列
1.简单数据结构类
(1)动态数组Arraylist
Arraylist是C#封装好的类,本质是一个object类型的数组,可以使用该类提供的方法进行增删改查。
using System.Collections;//需要引用命名空间
using System;
namespace Test
{
class Program
{
public static void Main(string[] args)
{
ArrayList array = new ArrayList();
//增 存储任意对象
array.Add(1);
array.Add("nihao");
array.Add(true);
array.Add(new object());
ArrayList array2 = new ArrayList(); //拼接array2
array2.Add(123);
array.AddRange(array2);//从后面依次累加
array.Insert(1,"1234567");//将元素插到指定位置
//删
array.Remove(1);//从前往后删除指定元素
array.RemoveAt(2);//移除第二个位置的元素
array.Clear();//清空
//
array.Add(1);
array.Add("nihao");
array.Add(true);
//改
array[1] = 999;
//查
Console.WriteLine(array[0]);//得到第0个位置的元素
bool position = array.Contains("nihao");//查看ArrayList是否有该元素
int index = array.IndexOf(true);//正向查找元素,返回的是索引位置,找不到为-1
index = array.LastIndexOf(true);//反向查找元素,返回的是索引位置,找不到为-1
//遍历
int count = array.Count;//元素长度
int capacity = array.Capacity;//容量 避免产生大量垃圾
for(int i = 0 ; i< array.Count ; i++)//for循环遍历
{
Console.WriteLine(array[i]);
}
foreach(var item in array)//迭代器遍历
{
Console.WriteLine(item);
}
//装箱拆箱
int num = 0;
array[0] = 1;//装箱 栈内存到堆内存
num = (int)array[0];//拆箱 堆内存到栈内存
}
}
}
(2)栈Stack
Stack是C#封装好的类,它的本质也是object [ ] 数组 , 只是封装了特殊的存储规则,stack 是栈存储容器 , 栈是一种先进后出的数据结构
先存入的数据后获取 , 后存入的数据先获取
using System.Collections;//需要引用命名空间
using System;
namespace Test
{
class Program
{
public static void Main(string[] args)
{
Stack stack = new Stack();
//增
stack.Push(1);
stack.Push("123");
stack.Push(true);
stack.Push(new object());
//取 栈中没有删的概念
Console.WriteLine(stack.Pop());//System.Object
Console.WriteLine(stack.Pop());//True
//查 只能查看栈顶的元素
Console.WriteLine(stack.Peek());//123
Console.WriteLine(stack.Peek());//123
bool have = stack.Contains(1);//true
//改 无法改变其中的元素,只可以压和弹
stack.Clear();//清空
stack.Push(1);
stack.Push(1.2f);
stack.Push("哈哈哈");
//遍历
Console.WriteLine(stack.Count);//3
foreach(var item in stack)//foreach遍历 是查看不是弹出 从栈顶到栈底
{
Console.WriteLine(item);
}
object[] o = stack.ToArray();//转换为object数组后遍历 从栈顶到栈底
for (int i = 0; i < o.Length; i++)
{
Console.WriteLine(o[i]);
}
while( stack.Count > 0 )//循环弹栈
{
object p = stack.Pop();
}
//装箱拆箱
int num = 0;
stack.Push(num);//装箱 栈内存到堆内存
stack.Pop();//拆箱 堆内存到栈内存
}
}
}
(3)队列Queue
Stack是C#封装好的类,它的本质也是object[]数组 , 只是封装了特殊的存储规则,Queue 是队列存储容器,队列是一种先进先出的数据结构
先存入的数据先获取 , 后存入的数据后获取
using System.Collections;//需要引用命名空间
using System;
namespace Test
{
class Program
{
public static void Main(string[] args)
{
Queue queue = new Queue();
//增
queue.Enqueue(1);
queue.Enqueue("123");
queue.Enqueue(true);
queue.Enqueue(new object());
//取
Console.WriteLine(queue.Dequeue());//1
Console.WriteLine(queue.Dequeue());//123
//查
Console.WriteLine(queue.Peek());//true
Console.WriteLine(queue.Peek());//true
bool have = queue.Contains(true);//true
//改 只能清空后改变
queue.Clear();
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);
//遍历
Console.WriteLine(queue.Count);//3
foreach(object item in queue)//foreach遍历 是查看不是取出 从队首到队尾
{
Console.WriteLine(item);
}
object[] o = queue.ToArray();//转换为object数组后遍历 从队首到队尾
for (int i = 0; i < o.Length; i++)
{
Console.WriteLine(o[i]);
}
while( queue.Count > 0 )//循环出列
{
object p = queue.Dequeue();
}
//装箱拆箱
int num = 0;
queue.Enqueue(num);//装箱 栈内存到堆内存
num = (int)queue.Dequeue();//拆箱 堆内存到栈内存
}
}
}
(4)哈希表Hashtable
Hashtable ( 又称散列表 ) 是基于键的哈希代码组织起来的 键 / 值 对,它的主要作用是高数据查询的效率
使用键来访问集合中的元素
using System.Collections;//需要引用命名空间
using System;
namespace Test
{
class Program
{
public static void Main(string[] args)
{
Hashtable hashtable = new Hashtable();
//增 键是唯一的
hashtable.Add(1,1);//键 1 ,值 1
hashtable.Add(true,"123");//键true ,值 123
hashtable.Add(false,false);//键false ,值 false
//删 只能通过键去删除
hashtable.Remove(1);//通过删除键 来删除值 如果没有键则无反应
hashtable.Clear();//清空
hashtable.Add(1,1);
hashtable.Add(2,2);
hashtable.Add("year",3);
hashtable.Add(true,3);
//查
Console.WriteLine(hashtable[true]);//3 通过键查值找不到返回空
bool have = hashtable.Contains("year");//true 键查找
bool havekey = hashtable.ContainsKey("year");//true 键查找
bool havevalue = hashtable.ContainsValue("123");//true 值查找
//改 只能改键对应的值 无法修改键
hashtable[true] = 100.9f;
//遍历
Console.WriteLine(hashtable.Count);//对数
//遍历所有键
foreach(object item in hashtable.Keys)//注意要加Keys
{
Console.WriteLine("键:"item);
Console.WriteLine("值:"hashtable[item]);
}
//遍历所有值
foreach(object item in hashtable.Values)//注意要加Values
{
Console.WriteLine("值:"item);
}
//键值对一起遍历
foreach(DictionaryEntry item in hashtable)//注意DictionaryEntry
{
Console.WriteLine("键:"item.Key"+值:"item.Value);
}
//迭代器遍历
IDictionaryEnumerator myEnumerator = hashtable.GetEnumerator();
bool flag = myEnumerator.MoveNext();
while(flag) // 判断之后有没有
{
Console.WriteLine("键:{0} 值:{1}",myEnumerator.Key,myEnumerator.Value);
flag = myEnumerator.MoveNext();
}
//装箱拆箱
int i = 0;
hashtable.Add(index,i);装箱 栈内存到堆内存
i = hashtable[index];//拆箱 堆内存到栈内存
}
}
}
2.泛型
泛型实现了类型参数化 , 达到代码重用目的,通过类型参数化来实现同一份代码上操作多种类型,泛型相当于类型占位符,定义类或方法时使用替代符代表变量类型,当真正使用类或者方法时再具体指定类型
泛型分类
泛型类和泛型接口
基本语法:
class 类名 < 泛型占位字母 >
interface 接口名 〈 泛型占位字母 >
泛型函数
基本语法 : 函数名 < 泛型占位字母 > ( 参数列表 )
注意 : 泛型占位字母可以有多个 , 用逗号分开
using System;
namespace Test
{
class TestClass<T>//泛型类(单参)
{
public T value;
}
class TestClass2<A,B>//泛型类(多参)
{
public A aValue;
public B bValue;
}
class Test2
{
public void TestFun<T>(T value)//泛型方法(单参)
{
Console.WriteLine(value);
}
public void TestFun<T,U,V>(T t,U u,V v)//泛型方法(多参)
{
}
public void TestFun1<T>()//泛型方法(逻辑处理)
{
T t = default(T);
}
public T TestFun1<T>()//泛型方法(返回值)
{
return default(T);
}
}
class Test2<T>//泛型类中的泛型方法 与Test2算作两个类,泛型也看做名字的一部分
{
public void Test<U>(U u)//泛型类中的泛型方法
{
}
}
interface TestInterface<T>//泛型接口
{
T value
{
get;
set;
}
}
class Test:TestInterface<int>//继承泛型接口
{
public int num;
public int value
{
get
{
return 0;
}
set
{
num = value;
}
}
}
class Program
{
public static void Main(string[] args)
{
//泛型类(单参)
TestClass<int> t = new TestClass<int>();
t.value = 10;//int类型
TestClass<float> f = new TestClass<float>();
f.value = 10.0f;//float类型
//泛型类(多参)
TestClass2<int,string> intstring = new TestClass2<int,string>();
intstring.aValue = 10;
intstring.bValue = "123";
//泛型方法
Test2 tt = new Test2();
tt.TestFun<string>("nihao");
//不同类型对象的相同逻辑处理就可以选择泛型
}
}
}
泛型约束
让泛型的类型有一定限制,关键字where,泛型约束一共有六种
using System;
namespace Test
{
//值类型 where 泛型字母:struct
class Test1<T> where T:struct
{
public T value;
public void TestFun<K>(K k) where K:struct
{
}
}
//引用类型 where 泛型字母:class
class Test2<T> where T:class
{
public T value;
public void TestFun<K>(K k) where K:class
{
}
}
//存在无参公共构造函数 where 泛型字母:new()
class Test3<T> where T:new() //必须是具有公共构造函数的非抽象函数类型
{
public T value;
}
//类约束 where 泛型字母:类名
class Test4<T> where T:Test1//某个类本身或者其派生类
{
public T value;
}
//接口约束 where 泛型字母:接口名
class Test5<T> where T:IFly
{
public T value;
}
//另一个泛型约束 where 泛型字母:另一个泛型字母
class Test6<T,U> where T:U//另一个泛型类型本身或者派生类型 T要么和U相同要么是U的派生
{
public T value;
public void TestFun<K,V>(K k) where K:V
{
}
}
//------------测试类------------
class Test1//用于Test3 Test4测试
{
public Test1()
{
}
}
class Test2:Test1//用于Test4测试
{
}
class Test3//用于Test4测试
{
}
interface IFly//用于Test5测试
{
}
class Test4:IFly//用于Test5测试
{
}
//------------测试类------------
class Program
{
public static void Main(string[] args)
{
//值类型
Test1<int> t1 = new Test1<int>();
t1.TestFun<float>(1.3f);
//引用类型
Test2<Random> t2 = new Test2<Random>();
t2.value = new Random();
//存在无参公共构造函数
Test3<Test1> t3 = new Test3<Test1>();
//某个类本身或者其派生类
Test4<Test1> t4 = new Test4<Test1>();
Test4<Test2> t4 = new Test4<Test2>();
//Test4<Test3> t4 = new Test4<Test3>();错误,必须是Test1类本身或者其派生类
//某个接口的派生类型
Test5<IFly> t5 = new Test5<IFly>();//接口本身或者派生接口
t5.value = Test4;//派生类
//另一个泛型类型本身或者派生类型
Test6<Test4,IFly> t6 = new Test6<Test4,IFly>();
}
}
}
约束的组合使用
class Test7<T> where T:class,new() //T必须是引用类型且具有无参的构造函数
{
}
多个泛型有约束
class Test7<T,K> where T:class,new() where K:struct //关键字where
{
}
3.常用泛型数据结构类
(1)列表List
-
List是C#封装好的类,本质是一个可变类型的泛型数组。
using System.Collections.Generic;//需要引用命名空间 using System; namespace Test { class Program { public static void Main(string[] args) { //声明 List<int> list1 = new List<int>(); List<int> list2 = new List<int>(); //增 list1.Add(1); list1.Add(2); list2.Add(3); list1.AddRange(list2); list1.Insert(0,999); //删 list1.Remove(1);//删除元素1 list1.RemoveAt(0);//删除第一个元素 list1.Clear();//清空 // list1.Add(1); list1.Add(2); //查 //Console.WriteLine(list1[0]);//得到指定位置的元素 bool have = list1.Contains(1);//查看元素是否存在 int index = list1.IndexOf(2);//正向返回查找值的下标 int lastIndex = list1.LastIndexOf(2);//反向返回查找值的下标 //改 list1[0] = 99; //遍历 int length = list1.Count;//长度 int capacity = list1.Capacity;//容量 for (int i = 0 ; i < list1.Count; i++) { Console.WriteLine(list1[i]); } foreach (var item in list1) { Console.WriteLine(item); } } } }
(2)字典Dictionary
- 可以将Dictionary理解为拥有泛型的Hashtable,只不过键值对类型从object变成了可以自己制定的泛型
using System.Collections.Generic;//需要引用命名空间
using System;
namespace Test
{
class Program
{
public static void Main(string[] args)
{
//声明
Dictionary<int,string> dictionary = new Dictionary<int,string>();//键int 值string
//增
dictionary.Add(1,"123");
dictionary.Add(2,"456");
dictionary.Add(3,"789");
//删
dictionary.Remove(1);
dictionary.Remove(4);//删除没有的键没有反应
dictionary.Clear();//清空
//
dictionary.Add(1,"123");
dictionary.Add(2,"456");
dictionary.Add(3,"789");
//查
Console.WriteLine(dictionary[1]);//123 通过键查看值
//Console.WriteLine(dictionary[4]);//返回不存在的键会报错
bool haveKey = dictionary.ContainsKey(1);//true 是否存在键为1的
bool haveValue = dictionary.ContainsValue("123");//true 是否存在值为123的
//改
dictionary[1] = "555";
//遍历
int index = dictionary.Count;//长度
foreach(var item in dictionary.Keys)//foreach遍历键值
{
Console.WriteLine(item);
Console.WriteLine(dictionary[item]);
}
foreach(var item in dictionary.Values)//遍历值
{
Console.WriteLine(item);
}
foreach (KeyValuePair<int,string> item in dictionary)//KeyValuePair遍历键值
{
Console.WriteLine("键{0},值{1}",item.Key,item.Value);
}
}
}
}
(3)顺序存储和链式存储
数据结构, 就是人定义的 存储数据 和 表示数据之间关系 的规则,常见的数据结构有数组 、 栈 、 队列 、 链表 、 树 、 图 、 堆 、 散列表等
顺序存储 :
用一组地址连续的存储单元依次存储线性表的各个数据元素
数组 、 stack 、 Queue 、 List 、 ArrayList是顺序存储
只是数组 、 Stack 、 Queue 的组织规则不同而已
链式存储 〈 链接存储 ) :
用一组任意的存储单元存储线性表中的各个数据元素
单向链表 、 双向链表 、 循环链表是链式存储
链式存储实现:
using System;
namespace Test
{
class LinkNode<T>//节点
{
public T value;
public LinkNode<T> nextNode;
public LinkNode(T value)
{
this.value = value;
this.nextNode = null;
}
}
class LinderList<T>//单链表
{
public LinkNode<T> head;//头结点
public LinkNode<T> tail;//尾节点
public void AddTail(T value)//尾插法
{
LinkNode<T> newNode = new LinkNode<T>(value);
if(head == null)//如果当前链表为空
{
head = newNode;
tail = newNode;
}
else
{
tail.nextNode = newNode;//让尾的下一个指向新节点
tail = newNode;//新节点变成新的尾巴
}
}
public void RemoveNode(T value)
{
if(head == null)
{
return;
}
if(head.value.Equals(value))
{
head = head.nextNode;//头结点变为下一个节点
if(head == null)//如果删除后头结点为空
{
tail = null;
}
return;
}
LinkNode<T> node = head;
while(node != null)
{
if(node.nextNode.value.Equals(value))//如果下一个节点的值与要删除的值相同
{
node.nextNode = node.nextNode.nextNode;//那么指向下下个节点
break;
}
node = node.nextNode;
}
}
}
class Program
{
public static void Main(string[] args)
{
LinderList<int> linderList1 = new LinderList<int>();
linderList1.AddTail(1);
linderList1.AddTail(2);
linderList1.AddTail(3);
linderList1.AddTail(4);
linderList1.AddTail(5);
linderList1.RemoveNode(1);//删除头结点
linderList1.RemoveNode(3);//删除中间节点
linderList1.RemoveNode(5);//删除尾节点
LinkNode<int> node = linderList1.head;
while(node!= null)
{
Console.WriteLine(node.value);
node = node.nextNode;
}
}
}
}
(4)泛型双向链表Linkedlist
Linkedlist是CSHARP封装好的类,他的本质是一个可变类型的泛型双向链表。
using System.Collections.Generic;//需要引用命名空间
using System;
namespace Test
{
class Program
{
public static void Main(string[] args)
{
//声明
LinkedList<int> linkedList = new LinkedList<int>();
//链表对象需要掌握两个类,一个是链表本身LinkedList,一个是链表节点类LinkedListNode
//增
linkedList.AddFirst(10);//在链表头部添加元素
linkedList.AddLast(20);//在链表尾部添加元素
linkedList.AddLast(3);//在链表尾部添加元素
linkedList.AddAfter(linkedList.Find(3),20);//在从头开始查找第一个节点值3后添加元素20
linkedList.AddBefore(linkedList.Find(10),1);//在从头开始查找第一个节点值10后添加元素1
linkedList.AddLast(3);//在链表尾部添加元素
Console.WriteLine("-------初始值------");
LinkedListNode<int> node = linkedList.First;
while (node != null)
{
Console.WriteLine(node.Value);
node = node.Next;
}
Console.WriteLine("-------------------");
//删
Console.WriteLine("---移除头尾和一个20--");
linkedList.RemoveFirst();//移除头结点
linkedList.RemoveLast();//移除尾结点
linkedList.Remove(20);//移除从头开始第一个等于该值节点
node = linkedList.First;
while (node != null)
{
Console.WriteLine(node.Value);
node = node.Next;
}
Console.WriteLine("-------------------");
linkedList.Clear();//清空链表
//
linkedList.AddLast(1);//在链表尾部添加元素
linkedList.AddLast(2);//在链表尾部添加元素
linkedList.AddLast(3);//在链表尾部添加元素
linkedList.AddLast(4);//在链表尾部添加元素
linkedList.AddLast(5);//在链表尾部添加元素
Console.WriteLine("-------新值------");
node = linkedList.First;
while (node != null)
{
Console.WriteLine(node.Value);
node = node.Next;
}
Console.WriteLine("-------------------");
//查
LinkedListNode<int> first = linkedList.First;
LinkedListNode<int> last = linkedList.Last;
Console.WriteLine("first:{0} , last:{1}",first.Value,last.Value);
Console.WriteLine("链表中存在2:{0}",linkedList.Contains(2));
node = linkedList.Find(2);//存在后可以返回该节点
Console.WriteLine("链表中存在6:{0}",linkedList.Contains(6));
//node = linkedList.Find(6);//若不存在则会报错
//改
linkedList.Find(2).Value = 4;//先得到节点,再修改值
//遍历
Console.WriteLine("-----foreach遍历---");
foreach (var item in linkedList) //通过迭代器处理可以直接得到里面的值
{
Console.WriteLine(item);
}
Console.WriteLine("-------------------");
Console.WriteLine("---从头节点遍历-----");
LinkedListNode<int> head = linkedList.First;
while (head != null)
{
Console.WriteLine(head.Value);
head = head.Next;
}
Console.WriteLine("-------------------");
Console.WriteLine("---从尾节点遍历-----");
LinkedListNode<int> tail = linkedList.Last;
while (tail != null)
{
Console.WriteLine(tail.Value);
tail = tail.Previous;
}
Console.WriteLine("-------------------");
}
}
}
(5)泛型栈和队列
using System.Collections.Generic;//需要引用命名空间
using System;
namespace Test
{
class Program
{
public static void Main(string[] args)
{
//声明 命名空间using System.Collections.Generic;
//使用上和Stack与Queue相同
Stack<int> stack = new Stack<int>;
Queue<int> queue = new Queue<int>;
}
}
}