常用泛型数据结构类
文章目录
- 常用泛型数据结构类
- 1、List
- 1、List的本质
- 2、声明
- 3、增删查改
- 4、遍历
- 思考 存储基类类型列表
- 2、Dictionary
- 1、Dictionary的本质
- 2、声明
- 3、增删查改
- 4、遍历
- 思考1 数字对应的大写
- 思考 2 字母出现的次数
- 3、顺序存储和链式存储
- 1、数据结构
- 2、线性表
- 3、顺序存储
- 4、链式存储
- 5、自己实现一个最简单的单向链表
- 6、顺序存储和链式存储的优缺点
- 思考 双向链表
- 4、Linkedlist
- 1、LinkedList
- 2、声明
- 3、增删查改
- 4、遍历
- 5、泛型栈和队列
- 总结 数据用法
1、List
1、List的本质
List是C#封装好的类,本质是一个可变类型的泛型数组
2、声明
List<int> list1 = new List<int>();
List<string> list2 = new List<string>();
List<string> listStr = new List<string>();
3、增删查改
增
list1.Add(11);
list2.AddRange(listStr);
list1.Insert(0,66);
删
//1.移除指定元素
list1.Remove(11);
//2、移除指定位置元素
list1.RemoveAt(0);
//3、清空
list1.Clear();
查
//1、查看指定位置元素
Console.WriteLine(list1[0]);
//2、查看元素是否存在
if (list1.Contains(11))
{
Console.WriteLine("存在");
}
//3、正向查找元素位置
int index = list1.IndexOf(11);
Console.WriteLine(index);
//4、反向查找元素位置
index = list1.LastIndexOf(11);
Console.WriteLine(index);
改
list1[0] = 22;
4、遍历
//长度
Console.WriteLine(list1.Count);
//容量
Console.WriteLine(list1.Capacity);
//for循环遍历
for (int i = 0; i < list1.Count; i++)
{
Console.WriteLine(list1[i]);
}
//迭代器遍历
foreach (int i in list1)
{
Console.WriteLine(i);
}
思考 存储基类类型列表
//一个Monster基类,Boss和Gablin类继承它
//在怪物类的构造函数中,将其存储到一个怪物List中
//遍历列表可以让Boss和Gablin对象产生不同攻击
Boss boss1 = new Boss();
Boss boss2 = new Boss();
Gablin Gablin1 = new Gablin();
Gablin Gablin2 = new Gablin();
for (int i = 0; i < Monster.monsters.Count; i++)
{
Monster.monsters[i].Atk();
}
abstract class Monster
{
public static List<Monster> monsters = new List<Monster>();
public Monster()
{
monsters.Add(this);
}
public abstract void Atk();
}
class Gablin : Monster
{
public override void Atk()
{
Console.WriteLine("哥布林的攻击");
}
}
class Boss : Monster
{
public override void Atk()
{
Console.WriteLine("Boss的攻击");
}
}
2、Dictionary
1、Dictionary的本质
可以将Dictionary理解为:拥有泛型的Hashtable
它是基于键的哈希代码组织起来的键值对
键值对类型从Hashtable的object变为了可以自己指定的泛型
2、声明
Dictionary<int,string> dictionary = new Dictionary<int,string>();
3、增删查改
增
//不能出现相同名的键
dictionary.Add(1, "aaa");
dictionary.Add(2, "bbb");
dictionary.Add(3, "ccc");
删
//1、只能通过键去删除
dictionary.Remove(3);
//2、清空
dictionary.Clear();
查
//1、通过键查看值,键找不到报错
Console.WriteLine(dictionary[2]);
//2、查看是否存在
//根据键检测
if (dictionary.ContainsKey(2))
{
Console.WriteLine("存在");
}
//根据值检测
if (dictionary.ContainsValue("bbb"))
{
Console.WriteLine("存在");
}
改
dictionary[1]="666";
4、遍历
1、遍历所有键
foreach (int item in dictionary.Keys)
{
Console.WriteLine(item);
Console.WriteLine(dictionary[item]);
}
2、遍历所有值
foreach(string item in dictionary.Values)
{
Console.WriteLine(item);
}
3、键值对遍历
foreach(KeyValuePair<int,string> pair in dictionary)
{
Console.WriteLine(pair);
}
思考1 数字对应的大写
//使用字典存储0~9的数字对应的大写文字
//提示用户输入一个不超过三位的数,提供一个方法,返回数的大写
try
{
Console.WriteLine("输入三位数");
Console.WriteLine(GetInfo(int.Parse(Console.ReadLine())));
}
catch
{
Console.WriteLine("wrong");
}
string GetInfo(int num)
{
Dictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(0, "零");
dictionary.Add(1, "壹");
dictionary.Add(2, "贰");
dictionary.Add(3, "叁");
dictionary.Add(4, "肆");
dictionary.Add(5, "伍");
dictionary.Add(6, "陆");
dictionary.Add(7, "柒");
dictionary.Add(8, "捌");
dictionary.Add(9, "玖");
int b = num / 100;
string str = "";
if (b != 0)
{
str += dictionary[b];
}
int s = num % 100 / 10;
if (s != 0 || str != "")
{
str += dictionary[s];
}
int g = num % 10;
str += dictionary[g];
return str;
}
思考 2 字母出现的次数
//计算每个字母出现的次数“Welcome to Unity World!”,使用字典存储,最后遍历,不区分大小写
Dictionary<char,int> dictionary = new Dictionary<char,int>();
string str = "Welcome to Unity World!";
str = str.ToLower();
for (int i = 0; i < str.Length; i++)
{
if (dictionary.ContainsKey(str[i]))
{
dictionary[str[i]]++;
}
else
{
dictionary.Add(str[i], 1);
}
}
foreach (char c in dictionary.Keys)
{
Console.WriteLine("{0}出现了{1}次", c, dictionary[c]);
}
3、顺序存储和链式存储
1、数据结构
数据结构是计算机存储、组织数据的规则
数据结构是指相互之间存在一种或多种特定关系的数据元素的集合
存储数据和表示数据之间关系的规则
常用的数据结构
数组、栈、队列、链表、树、图、堆、散列表
2、线性表
线性表是一种数据结构,是由n个具有相同特性的数据元素的有限序列
例如:数组、ArrayList、Stack、Queue、链表
3、顺序存储
顺序存储和链式存储是数据结构中两种存储结构
数组、Stack、Queue、List、ArrayList 顺序存储
数组、Stack、Queue的组织规则不同
顺序存储:用一组地址连续的存储单元依次存储线性表的各个数据元素
4、链式存储
单向链表、双向链表、循环链表 链式存储
链式存储(链接存储):用一组任意的存储单元存储线性表中的各个数据元素
5、自己实现一个最简单的单向链表
LinkedList<int> link = new LinkedList<int>();
link.Add(1);
link.Add(2);
link.Add(3);
link.Add(4);
LinkedNode<int> node = link.head;
while (node != null)
{
Console.WriteLine(node.value);
node = node.nextNode;
}
link.Remove(2);
node = link.head;
while (node != null)
{
Console.WriteLine(node.value);
node = node.nextNode;
}
link.Add(5);
node = link.head;
while (node != null)
{
Console.WriteLine(node.value);
node = node.nextNode;
}
/// <summary>
/// 单向链表节点
/// </summary>
/// <typeparam name="T"></typeparam>
class LinkedNode<T>
{
public T value;
public LinkedNode<T> nextNode;
public LinkedNode(T value)
{
this.value = value;
}
}
/// <summary>
/// 单向链表类 管理
/// </summary>
/// <typeparam name="T"></typeparam>
class LinkedList<T>
{
public LinkedNode<T> head;
public LinkedNode<T> last;
public void Add(T value)
{
LinkedNode<T> node = new LinkedNode<T>(value);
if (head == null)
{
head = node;
last = node;
}
else
{
last.nextNode = node;
last = node;
}
}
public void Remove(T value)
{
if(head== null)
{
return;
}
if (head.value.Equals(value))
{
head = head.nextNode;
if (head == null)
{
last = null;
}
return;
}
LinkedNode<T> node = head;
while (node.nextNode != null)
{
if (node.nextNode.value.Equals(value))
{
node.nextNode = node.nextNode.nextNode;
break;
}
node = node.nextNode;
}
}
}
6、顺序存储和链式存储的优缺点
增、删:链式存储优于顺序存储
查、改:顺序存储优于链式存储
思考 双向链表
//实现一个双向链表,并提供以下方法和属性
//数据的个数,头节点,尾节点
//增加数据到链表最后
//删除指定位置节点
LinkedList<int> link = new LinkedList<int>();
link.Add(2);
link.Add(3);
link.Add(4);
link.Add(5);
//正向访问
LinkedNode<int> node = link.Head;
while (node != null)
{
Console.WriteLine(node.value);
node = node.nextNode;
}
link.RemoveAt(5);
//反向访问
node = link.Last;
while (node != null)
{
Console.WriteLine(node.value);
node = node.frontNode;
}
class LinkedNode<T>
{
public T value;
public LinkedNode<T> frontNode;
public LinkedNode<T> nextNode;
public LinkedNode(T value)
{
this.value = value;
}
}
class LinkedList<T>
{
private int count;
private LinkedNode<T> head;
private LinkedNode<T> last;
public int Count
{
get { return count; }
}
public LinkedNode<T> Head
{
get { return head; }
}
public LinkedNode<T> Last
{
get { return last; }
}
//添加
public void Add(T value)
{
LinkedNode<T> node = new LinkedNode<T>(value);
if (head == null)
{
head = node;
last = node;
}
else
{
//添加到尾部
last.nextNode = node;
//尾部添加的节点 记录自己的上一个节点
node.frontNode = last;
//将新加节点记录为last
last = node;
}
count++;
}
//删除
public void RemoveAt(int index)
{
if (index >= count || index < 0)
{
Console.WriteLine("删除失败");
return;
}
int tempCount = 0;
LinkedNode<T> tempNode = head;
while (true)
{
//计数找到对应节点
if (tempCount == index)
{
//移除节点
if (tempNode.frontNode !=null)
{
tempNode.frontNode.nextNode = tempNode.nextNode;
}
if (tempNode.nextNode != null)
{
tempNode.nextNode.frontNode = tempNode.frontNode;
}
//若移除了头节点,则将头指向下一个节点
if (index == 0)
{
head = head.nextNode;
}
//将倒数第二个作为尾节点
else if (index == count-1)
{
last = last.frontNode;
}
count--;
break;
}
//每次下移一位
tempNode = tempNode.nextNode;
tempCount++;
}
}
}
4、Linkedlist
1、LinkedList
LinkedList是一个C#为我们封装好的类
它的本质是一个可变类型的泛型双向链表
2、声明
//链表LinkedList 链表节点类LinkedListNode
LinkedList<int> link = new LinkedList<int>();
LinkedList<string> link2 = new LinkedList<string>();
3、增删查改
LinkedList<int> link = new LinkedList<int>();
增
1、在链表头部添加元素
link.AddFirst(1);
2、在链表尾部添加元素
link.AddLast(20);
3、在某个节点之前添加元素
LinkedListNode<int> c = link.Find(2);
link.AddBefore(c, 19);
4、在某个节点之后添加元素
link.AddAfter(c, 21);
删
1、移除头节点
link.RemoveFirst();
2、移除尾节点
link.RemoveLast();
3、移除指定节点
link.Remove(20);
查
1、头节点
LinkedListNode<int> first = link.First;
2、尾节点
LinkedListNode<int> last = link.Last;
3、找到指定值节点
LinkedListNode<int> node = link.Find(20);
Console.WriteLine(node.Value);
4、判断是否存在
if (link.Contains(20))
{
Console.WriteLine("存在");
}
改
先得到节点,再该值
link.First.Value = 10;
4、遍历
1、foreach遍历
foreach (int i in link)
{
Console.WriteLine(i);
}
2、通过节点遍历
从头到尾
LinkedListNode<int> nowNode = link.First;
while (nowNode != null)
{
Console.WriteLine(nowNode.Value);
nowNode = nowNode.Next;
}
从尾到头
nowNode = link.Last;
while (nowNode != null)
{
Console.WriteLine(nowNode.Value);
nowNode = nowNode.Previous;
}
5、泛型栈和队列
Stack<int> s = new Stack<int>();
Queue<int> q = new Queue<int>();
总结 数据用法
普通线性表:
数组、List、LinkedList
ArrayList:固定的不变的一组数据
List:经常改变,经常通过下标查找
LinkedList:不确定长度,经常临时插入改变,查找次数少
先进后出
Stack
对于一些可以利用先进后出存储特点的逻辑
比如:UI面板显隐规则
先进先出
Queue
对于一些可以利用先进先出存储特点的逻辑
比如:消息队列,实时存放,慢慢依次处理
键值对
Dictionary
需要频繁查找的,有对应关系的数据
比如一些数据存储,id对应数据内容