数据结构
什么是数据结构?
数据结构是一种或多种特定关系的数据元素集合 数据结构=数据+结构
另:Java的意义
.java–>.class–>根据.class文件所产生的的类,才具有意义
集合类
- 为什么需要集合类?
很多情况下,我们需要对一组对象进行操作。而且很可能事先并不知道到底有多少个对象。为了解决这个问题呢,Java 就提供了集合类供我们使用。(存储更多类型问题, 扩容问题, 内存空间浪费问题, 数据查找问题, 数据删除问题等等) 去理解什么是集合类的时候可以在功能上与数据类比,结构上模仿了数据结构中的集合,线性表,树等等,就是形式上与数据结构类比。 - 集合类的特点
a. 只能存储引用数据类型
b. 可以自动地调整自己的大小 - 数组和集合类都是容器,它们有何不同?
a. 数组可以存储基本数据类型的数据,集合不可以。
b. 数组的长度是固定的,集合可以自动调整自己的大小。
c. 数组的效率高,相对来说集合效率比较低。
d. 数组没有API,集合有丰富的API。
数据结构和Java关系
本质上,数据结构和Java没有任何关系。但是,在Java的集合类中,为了更方便的构建,Java采用了数据结构的结构(数据结构的构建方式),用于描述了一些JAVA对象的底层数据的组成关系 。模仿了数据结构中的结构(就是类似于链表,栈,这种结构)从而更方便的存储数据。
结构
结构的表示可以分为两种:顺序存储结构 (顺序映像) 和 链式存储结构 (非顺序映像)。
顺序映像:借助元素在存储器中的相对位置来表示数据元素之间的逻辑关系。(数组)
非顺序映像:借助指示元素存储地址的”指针”,来表示数据元素的逻辑关系。(链表)
数据结构的基本结构
集合,线性表,树,图
数组
数组的下标为什么从0开始
从两个层面出发
第一层:历史遗留问题,在以前硬件资源是很昂贵的
第二层:方便计算
数组最主要的特点
数组是连续存储随机访问的
数组为什么比链表效率高
数组是连续存储的所以根据首地址,可以随意查询,
增加
最坏情况 o(n)
最好情况 o(1)
平均情况(平均移动n/2个元素): o(n)
删除 (保证元素的顺序)
最好情况:O(1)
最坏情况:移动n-1个元素,O(n)
平均情况:移动(n-1)/2个元素,O(n)
查找
a. 根据索引查找元素:O(1)
b. 查找数组中与特定值相等的元素
①大小无序:O(n)
②大小有序:O(log2n)
数组: 添加和删除慢 o(n)
查找快: 尤其根据下标查找 大小有序的折半查找
作业
构建一个链表, 查找链表的中间元素
解题思想:分为快慢指针,快指针一次走两个,慢指针一次走一个,当快指针走到链表结尾,慢指针更好走到中间。
public class GetMid {
public static void main(String[] args) {
//构建链表
Node one = new Node(null, "one");
Node two = new Node(null, "two");
Node three = new Node(null, "three");
Node four = new Node(null, "four");
Node five = new Node(null, "five");
Node six = new Node(null, "six");
one.next = two;
two.next = three;
three.next = four;
four.next = five;
five.next = six;
six.next = null;
System.out.println(getMidNode(two).value);
}
public static Node getMidNode(Node begin) {
Node quick = begin;
Node slow = begin;
//分为快慢两个指针
while (quick.next != null && quick.next.next != null) {
quick = quick.next.next;
slow = slow.next;
}
return slow;
}
}
class Node {
String value;
Node next;
public Node(Node next, String value) {
this.value = value;
this.next = next;
}
public Node() {
}
}
判断一个链表是否有环
结题思路:分为两个快慢指针,如果链表中有环,那么在环中,快慢指针一定会相遇
Q1:快指针会越过慢指针吗?
不会,在环中,相当于快指针一直在追慢指针,相对于慢指针,快指针一次移动一个,并不会越过。也可以这么想,对于快指针和慢指针,他们只会出现两种情况:慢指针在快指针前一个,或慢指针在快指针前两个,对于这两种情况,无论怎么运行,快指针都不会越过慢指针。
对于代码问题,一般要转变成数学问题
public class JudgeCircular {
public static void main(String[] args) {
// 构建链表
CNode first = new CNode(null, "first", true);
CNode second = new CNode(null, "second", true);
CNode third = new CNode(null, "third", true);
CNode forth = new CNode(null, "forth", true);
CNode fifth = new CNode(null, "fifth", true);
first.next = second;
second.next = third;
third.next = forth;
forth.next = fifth;
fifth.next = second;
System.out.println(judge(fifth));
}
public static boolean judge(CNode begin) {
CNode quick = begin;
CNode slow = begin;
while (quick != null && quick.next != null) {
quick = quick.next.next;
slow = slow.next;
if (slow == quick) {
return true;
}
}
return false;
}
}
class CNode {
CNode next;
String val;
boolean judgeC;
public CNode(CNode next, String val, boolean judgeC) {
this.next = next;
this.val = val;
this.judgeC = judgeC;
}
public CNode() {
}
}