数据结构
计算机中存储、组织数据的方式
数据结构是一种具有一定逻辑关系,在计算机中应用某种存储结构,并且封装了相应操作的数据元素集合。
它包含三方面的内容,逻辑关系、存储关系及操作。
不同种类的数据结构适合于不同种类的应用,而部分甚至专门用于特定的作业任务。
例如,计算机网络依赖于路由表运作,B 树高度适用于数据库的封装。
常见数据结构
线性结构
线性结构指的是数据元素之间存在着“一对一”的线性关系的数据结构
数组(Array)、队列(Queue)、链表(Linked List)、栈(Stack)
非线性结构
非线性结构中各个数据元素不再保持在一个线性序列中,每个数据元素可能与
零个或者多个其他数据元素发生联系。根据关系的不同,可分为层次结构和群结构。
堆(Heap)、散列表(Hash table)、树(Tree)、图(Graph)
数组
特征
- 最简单、最常用的结构。
- 线性结构,所以内存空间是连续的
- 存储有限个具有相同类型的数据
优点
内存空间连续,所以存在以下优点
- 根据索引进行查找、修改时效率高
- 按照索引遍历数组方便
缺点
也因为内存空间的连续,所以也存在一些缺点
- 在数组非结尾位置进行插入、删除操作时,导致后面的元素被迫移动,效率低
- 内存空间固定,无法自动扩容
- 只能存储同一种类型的数据
手撸代码
添加
头部插入
public static void main(String[] args) {
String[] array = new String[3];
headAdd(array, "hello1");
headAdd(array, "hello2");
headAdd(array, "hello3");
headAdd(array, "hello4");
for (String i : array) {
System.out.print(i + " ");
}
// 添加:hello4,数组空间已满!
// hello3 hello2 hello1
}
public static void headAdd(String[] array, String str) {
int index = array.length;
if (null != array[index-1]) {
System.out.println("添加:" + str + ",数组空间已满!");
}
for (int i = index - 2; i > 0; i--) {
String arr = array[i];
if (arr != null) {
array[i+1] = arr;
}
}
array[0] = str;
}
尾部插入
public static void main(String[] args) {
String[] array = new String[3];
tailAdd(array, "hello1");
tailAdd(array, "hello2");
tailAdd(array, "hello3");
tailAdd(array, "hello4");
for (String i : array) {
System.out.print(i + " ");
}
// 添加:hello4,数组空间已满!
// hello1 hello2 hello3
}
public static void tailAdd(String[] array, String str) {
int index = array.length;
if (null != array[index-1]) {
System.out.println("添加:" + str + ",数组空间已满!");
return;
}
for (int i = 0; i < index; i++) {
String arr = array[i];
if (arr == null) {
array[i] = str;
break;
}
}
}
指定位置插入
public static void main(String[] args) {
String[] array = new String[3];
appointAdd(array, "hello1", 1);
appointAdd(array, "hello2", 1);
for (String i : array) {
System.out.print(i + " ");
}
// null hello2 hello1
}
public static void appointAdd(String[] array, String str, int x) {
int index = array.length;
if (x >= index) {
System.out.println("下标越界!");
return;
}
if (null != array[index-1]) {
System.out.println("添加:" + str + ",数组空间已满!");
return;
}
for (int i = index - 1; i >= 0; i--) {
if (array[i] != null) {
array[i+1] = array[i];
}
if (i == x) {
array[i] = str;
break;
}
}
}
修改
public static void main(String[] args) {
String[] array = new String[3];
appointAdd(array, "hello1", 1);
update(array, "hello2", 1);
for (String i : array) {
System.out.print(i + " ");
}
// null hello2 null
}
public static void update(String[] array, String str, int x) {
int index = array.length;
if (x >= index) {
System.out.println("下标越界!");
return;
}
array[x] = str;
}
删除
public static void main(String[] args) {
String[] array = new String[3];
appointAdd(array, "hello1", 1);
appointAdd(array, "hello2", 1);
update(array, "hello3", 0);
delete(array, 0);
for (String i : array) {
System.out.print(i + " ");
}
// hello2 hello1 null
}
public static void delete(String[] array, int x) {
int index = array.length;
if (x >= index) {
System.out.println("下标越界!");
return;
}
for (int i = x; i < index; i++) {
if (i < index - 1) {
array[i] = array[i+1];
array[i+1] = null;
}
}
}
查找
public static void main(String[] args) {
String[] array = new String[3];
appointAdd(array, "hello1", 1);
appointAdd(array, "hello2", 1);
update(array, "hello3", 0);
get(array, 1);
for (String i : array) {
System.out.print(i + " ");
}
// 查询数据为:hello2
// hello3 hello2 hello1
}
public static void get(String[] array, int x) {
int index = array.length;
if (x >= index) {
System.out.println("下标越界!");
return;
}
System.out.println("查询数据为:" + array[x]);
}
总结
根据上面代码可以看出
效率最高的是修改、查询,直接根据索引位置就可以达到预期效果;
其次是尾部插入,需要循环找到为空的最后位置;
最后是头部插入、指定位置插入、删除;因为还需要移动其他元素位置;
适用场景
频繁查询,对存储空间要求不大,很少增加和删除的情况。