数据结构梳理
原创
©著作权归作者所有:来自51CTO博客作者刘大米kk的原创作品,请联系作者获取转载授权,否则将追究法律责任
基础数据类型
string & stringbuilder
- string主要用于公共API、读取性能高、占用内存小;不可变,天然线程同步。
- stringbuilder主要用于string拼接,修改性能好;可变,非线程同步。
数组
关键词:长度固定,顺序
以下代码演示内容
public class BasicDatatype : MonoBehaviour
{
//声明和初始化的3种方式
int[] array1 = new int[3] { 1, 4, 5 };
int[] array2;
int[] array3 = { 4, 6 };
// Start is called before the first frame update
void Start()
{
array2 = new int[6];//没有赋值的时候默认所有元素都是0;可以不赋值但是不能不指定长度
//以下展示数组遍历
for(int i=0; i<array1.Length; i++)
{
Debug.Log(array1[i]);
}
}
}
ArrayList
关键词:对象的有序集合、动态数组
对象是object类型,需要装箱和拆箱
动态意味着不用固定长度,会自动调整大小
以下代码演示的内容:
- 声明和初始化
- 增删改查
- 常见属性:Count、Contains、IndexOf
- 常见方法:Insert、Remove、Clear、Reverse、Sort
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicDatatype : MonoBehaviour
{
//这是声明和初始化
ArrayList arrayList = new ArrayList();
int[] array = { 1, 7, 8 };
string[] str = { "kk", "pp" };
// Start is called before the first frame update
void Start()
{
//为动态数组添加单个元素
arrayList.Add(34);
arrayList.Add(18);
arrayList.Add(25);
//添加一个数组
arrayList.AddRange(array);
arrayList.AddRange(str);
//修改一个元素
arrayList[1] = 100;
//遍历动态数组
foreach(var v in arrayList)
{
Debug.Log(v);
}
//一些其他的常用属性
Debug.Log(arrayList.Count);//返回长度
print(arrayList.Contains(12));//返回布尔值
Debug.Log(arrayList.IndexOf(25));//返回元素的下标,这里应该返回2
Debug.Log(arrayList.IndexOf(2));//没有的话应该返回-1
//一些其他常用的方法
arrayList.Insert(1, 12);//在arraylist的第1位后面插入12
arrayList.Insert(0, "star");
arrayList.Remove(12);//第一次遇到的12将会被删掉;如果不包含这个值就没有作用
arrayList.Reverse();//逆转
//arrayList.Sort();//进行排序,但是如果前面的过程中没有控制好数据类型,比如我们这里加入了字符串,排序就会出错
arrayList.Clear();//清除其内容
}
}
List
关键词:泛型类集合
类似ArrayList,但是无需装箱和拆箱,类型安全
public class BasicDatatype : MonoBehaviour
{
List<int> list = new List<int>();
void Start()
{
list.Add(2);
list.Add(7);
Debug.Log(list.Count);
//很多内容都和arraylist很像,但是因为类型安全,所以更推荐用L
}
}
HashTable 哈希表
关键词:键值对
用object类型,和ArrayList一样,类型不安全
以下代码演示的内容:
- 声明和初始化
- 增删改查
- 常见属性:Count、Contains、ContainsKey
- 常见方法:Remove、Clear
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicDatatype : MonoBehaviour
{
Hashtable ht = new Hashtable();
void Start()
{
//增
ht.Add("1", 100);
ht.Add("2", 300);
ht.Add(3, 800);
//删
ht.Remove(3);//清除键为3的键值对
ht.Clear();//全部清除
//改
ht["1"] = 900;
//查
Debug.Log(ht["1"]);
//获得所有的键
ICollection key = ht.Keys;
//遍历
foreach(var v in key)
{
Debug.Log(ht[v]);
}
//以下是属性
Debug.Log(ht.Count);//长度
Debug.Log(ht.ContainsKey("1"));//按键查找,返回布尔值
Debug.Log(ht.Contains(100));//按值查找,返回布尔值
}
}
Dictionary字典
关键词:用泛型类做键值对
以下两对关系很像:
- HashTable(object类型,类型不安全)——>Dictionary(泛型,类型安全)
- ArrayList(object类型,类型不安全)——>List(泛型,类型安全)
以下代码演示的内容:
- 声明和初始化
- 增删改查
- 常见属性:Count、Contains、ContainsKey
- 常见方法:Remove、Clear
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicDatatype : MonoBehaviour
{
Dictionary<string, string> dic = new Dictionary<string, string>();
void Start()
{
//增
dic.Add("1", "200");
dic.Add("3", "600");
//删
dic.Remove("3");
dic.Clear();
//改
dic["3"] = "kk";
//查
Debug.Log(dic["3"]);
//常用属性
Debug.Log(dic.ContainsKey("1"));
//遍历
foreach(KeyValuePair<string, string> kvp in dic)
{
Debug.Log(kvp.Key + ":" + kvp.Value);
}
}
}
HashSet
关键词:不能重复的序列表
以下代码演示的内容:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicDatatype : MonoBehaviour
{
HashSet<int> hs1 = new HashSet<int>();
HashSet<string> hs2 = new HashSet<string>();
HashSet<int> hs3 = new HashSet<int>();
void Start()
{
//增加
hs1.Add(1);
hs1.Add(2);
hs1.Add(2);
//计数
Debug.Log(hs1.Count);
hs3.Add(1);
hs3.Add(3);
hs3.Add(3);
//两个集合之间的运算
hs1.IntersectWith(hs3);//返回值是交集的部分
hs1.UnionWith(hs3);
hs1.ExceptWith(hs3);
hs1.SymmetricExceptWith(hs3);
//遍历
foreach (var v in hs1)
{
Debug.Log(v);
}
//没有自带的排序,想要排序只能走List
}
}
ListNode链表
关键词:泛型
- list、数组的插入和删除需要移位,但是索引方便,不用遍历
- 链表的插入和删除不用移位,但是索引的时候需要遍历
以下代码演示主要的代码功能:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicDatatype : MonoBehaviour
{
LinkedList<int> linkList = new LinkedList<int>();//声明一个链表
LinkedListNode<int> node;//声明一个节点
LinkedListNode<int> next;
void Start()
{
node = linkList.AddFirst(2);
linkList.AddAfter(node, 6);//在后面加
node = linkList.AddBefore(node, 1);//在前面加
next = linkList.AddAfter(node, 2);
//查
Debug.Log(linkList.Count);
Debug.Log(linkList.First.Value);
Debug.Log(linkList.Last.Value);
if (node.Previous != null)
Debug.Log(node.Previous.Value);
if (node.Next != null)
Debug.Log(node.Next.Value);
//插入
next = linkList.AddAfter(node, 3);
Debug.Log(node.Next.Value);
}
}
Stack
关键词:先进后出
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicDatatype : MonoBehaviour
{
Stack st = new Stack();
void Start()
{
st.Push("a");
st.Push("b");
st.Push("c");
object top = st.Pop();//出栈
object peek = st.Peek();//拿到栈顶的元素
Debug.Log(top.ToString());
Debug.Log(peek.ToString());
Debug.Log(st.Count);//拿到数量
//遍历
foreach(var v in st)
{
Debug.Log(v);
}
}
}
Queue
关键词:先进先出
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicDatatype : MonoBehaviour
{
Queue queue1 = new Queue();//object类型
Queue<int> queue2 = new Queue<int>();//泛型类
void Start()
{
//增
queue1.Enqueue("kkk");
queue1.Enqueue(3);
//删
Debug.Log(queue1.Dequeue());//输出kkk,也会改变queue1的值
//遍历
foreach (var v in queue1)
{
Debug.Log(v);
}
//其他的方法:Count/Contains/Clear也都有
}
}
手写堆栈和队列
栈
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class MyStack//这是一个栈
{
//这是栈里的每一个元素的数据类型,用链表来实现
class StackData
{
public StackData nextItem;//下一个
public object topData;//自己的值
public StackData(StackData next, object data)//这是构造函数
{
this.nextItem = next;//下一个
this.topData = data;//值
}
}
StackData top;//栈顶
//写Push方法
public void Push(object data)
{
top = new StackData(top, data);//入栈
}
public object Pop()
{
object obj = top.topData;
top = top.nextItem;
return obj;//拿到顶部的出栈数据
}
}
public class BasicDatatype : MonoBehaviour
{
void Start()
{
MyStack myStack = new MyStack();
myStack.Push(33);
myStack.Push("kkk");
object obj = myStack.Pop();
Debug.Log(obj.ToString());
}
}
队列
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class MyQueue
{
class QueueData
{
public QueueData nextItem;
public object topData;
public QueueData(QueueData last, object data)
{
this.nextItem = last;
this.topData = data;
}
public QueueData(object data)
{
this.topData = data;
}
}
QueueData top;
QueueData last;
public void EnQueue(object data)
{
if (top == null)//如果队列为空
{
top = new QueueData(data);
last = top;
}
else
{
last = new QueueData(last, data);
}
}
public object DeQueue()
{
object obj = top.topData;
top = top.nextItem;
return obj;
}
}
public class BasicDatatype : MonoBehaviour
{
void Start()
{
MyQueue myQueue = new MyQueue();
myQueue.EnQueue("kkk");
myQueue.EnQueue("222");
myQueue.EnQueue(145);
Debug.Log(myQueue.DeQueue());//应该是kkk
}
}
树 & 二叉树
树
(1)概念
本质:树是n个节点的有限集,n=0时称为空树。在任意一棵非空树中,有且仅有一个根结点;当n大于1的时候,其余结点可以分为m个互不相交的有限集。是一种一对多的数据结构。
一些派生概念:
- 结点的度:结点拥有的子树数量
- 叶结点/终端结点:度为0 的结点
- 非终端结点/分支结点/内部结点:度不为0的结点
- 树的度(Degree):树内各结点的度的最大值
- 树的深度/高度(Depth):树中结点的最大层次
- 树的层次(Level):从根开始定义起,根为第一层,根的孩子是第二层
- 有序树:各子树看成是从左到右有次序的;无序树:反之。
(2)特点
n>0的时候根节点是唯一的;m>0 的时候,子树的个数没有限制,但是一定是不相交的。
线性表和树的对比(图片来自《大话数据结构》一书):
二叉树(Binary Tree)
(1)概念
二叉树是一种特殊的树,二叉树是n个结点的有限集合,该集合可以为空或由一个根节点和左右两个互不相交的二叉树组成。
(2)特点
- 度是2
- 左子树和右子树是有序的
- 即使只有一棵树,仍然需要区分左子树和右子树
(3)各种形态
- 斜树:分为左斜树(所有的结点都只有左子树的二叉树)和右叉树(所有的结点都只有右子树的二叉树);这就可以是线性表,线性表可以看作树的特殊表现形式。
- 满二叉树:所有度不为0的结点都有左子树和右子树,并且所有的叶子都在同一层上。
- 完全二叉树:可以理解为满二叉树的最底层可以是不满的
- 同样结点数的二叉树,完全二叉树的深度是最小的
- 叶子结点只出现在最下两层
(5)遍历二叉树
- 前序遍历:根节点-左子树-右子树
- 中序遍历:左子树-根节点-右子树
- 后序遍历:右子树-根节点-左子树
- 层序遍历:按层级来
Tips:中序序列可以与先序序列、后序序列、层序序列中的任意一个来构建唯一的二叉树。
图
- 顶点的度:和这个顶点相连的边的条数;有向图中可以分为出度和入度。
- 权值:顶点和边的量化的属性,分为点权和边权
- 分类:有向图(所有的边都有方向)和无向图(所有的边都是双向的)
- 存储方式:邻接矩阵+邻接表
- 操作:
- 遍历:广度优先遍历(BFS)、深度优先遍历(DFS)