List、 Set、 数据结构、Collections
数据结构
当你用着java里面的容器类很爽的时候,你有没有想过,怎么ArrayList就像一个无限扩 充的数组,也好像链表之类的。好用吗?好用,这就是数据结构的处,只不过你在不知不觉中使用了。
现实世界的存储,我们使用的工具和建模。每种数据结构有自己的优点和缺点,想想如果Google的数据用的是数组的存储,我们还能方便地查询到所需要的数据吗?而算法,在这么多的数据中如何做到最快的插入,查找,删除,也是在追求更快。
我们java是面向对象的语言,就好似自动档轿车, C语言好似手动档吉普。数据结构呢?题速箱的工作原理。你完全可以不知道变速箱怎样工作,就把自动档的车子从A点开到B点,且未必就比懂得的人慢。写程序这件事,开车-样,经验可以起到很大作用,但如果你不知道底层是怎么工作的,就永远只能开车,既不会修车,也不能造车。当然了,数据结构内容比较多,细细的学起来也是相对费功夫的,可能达到一蹴而就。我们将常见的数据结构:堆栈、队列、数组、链表和红黑树几种给大家介绍一 下,作为数据结构的入门,了解- -下它们的特点即可。
栈(stack)
队列(queue)
数据结构----数组与链表结构
数组:增删慢,查询块
链表:查询慢,易于增删
单项链表只有两个部分,自己的地址和数据,他这样画错了。
双向链表有三部分,自己的地址和数据以及下一个节点的 地址
数据结构----树
二叉树与查找树/排序树
二叉树分支不能超过两个
排序树/查找树:在二叉树的基础上,元素大小有顺序的:左子树小,右子树大
平衡树与不平衡树
红黑树
红黑树:
特点:趋近于平衡树,查询的速度非常快
约束:
1.节点可以是红色或者黑色的
2.根节点是黑色的
3.叶子节点(空节点)是黑色的
4.每个红色节点的子节点必须都是黑色的
5.任何-个节点到其每个叶子节点的所有路径
.上的黑色节点数相同
List集合
List接口:
特有的方法:
void add(int index,E element): 将指定元素,添加到该集合中指定位置
E get(int index)返回此列表中指定位置的元素。
E set(int index,E element)用指定的元素(可选操作)替换此列表中指定位置的元素。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*List接口:
特有的方法:
void add(int index,E element): 将指定元素,添加到该集合中指定位置
E get(int index)返回此列表中指定位置的元素。
E set(int index,E element)用指定的元素(可选操作)替换此列表中指定位置的元素。
*/
public class LsitTest01 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();//多态
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
System.out.println(list);//这里输出不是地址,因为重写了tostring
list.add(1,"hello World");//void add(int index,E element): 将指定元素,添加到该集合中指定位置
list.set(0,"123");//E get(int index)返回此列表中指定位置的元素。
//for循环遍历
for (int i = 0; i <list.size() ; i++) {
System.out.print(list.get(i));
}
System.out.println();
//迭代器遍历
Iterator<String> it = list.iterator();
while (it.hasNext()){
System.out.print(it.next());
}
System.out.println();
//增强for遍历
for (String s : list) {
System.out.print(s);
}
}
}
常见面试笔试题Arraylist,LinkedList,Vector的区别
LinkedList集合
特点
1.链表结构,查询慢,增删快
2.API中包含了很多操作首尾元素的方法
特有方法:
public void addFirst(E e)在该列表开头插入指定的元素。
public void addLast(E e)将指定的元素追加到此列表的末尾。
public E getFirst()返回此列表中的第一 个元素。
public E getLast()返回此列表中的最后一 个元素。
public E removeFirst()从此列表中删除并返回第一 个元素。
public E removeLast()从此列表中删除并返回最后一 -个元素。
public void push(E e) 将元素推送到由此列表表示的堆栈上。换句话说,在该列表的前面插入元素。
此方法相当FaddFirst(E)。
public E pop()从此列表表示的堆栈中弹出一 个元素。 换句话说,删除并返回此列表的第一 个元素。
此方法相当FremoveFirst()。
import java.util.LinkedList;
/*LinkedList集合
特点
1.链表结构,查询慢,增删快
2.API中包含了很多操作首尾元素的方法
特有方法:
public void addFirst(E e)在该列表开头插入指定的元素。
public void addLast(E e)将指定的元素追加到此列表的末尾。
public E getFirst()返回此列表中的第一 个元素。
public E getLast()返回此列表中的最后一 个元素。
public E removeFirst()从此列表中删除并返回第一 个元素。
public E removeLast()从此列表中删除并返回最后一 -个元素。
public void push(E e) 将元素推送到由此列表表示的堆栈上。换句话说,在该列表的前面插入元素。
此方法相当FaddFirst(E)。
public E pop()从此列表表示的堆栈中弹出一 个元素。 换句话说,删除并返回此列表的第一 个元素。
此方法相当FremoveFirst()。
*/
public class ListTest02 {
public static void main(String[] args) {
show01();
show02();
}
private static void show02() {
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");
System.out.println(list.removeFirst());
System.out.println(list.removeLast());
System.out.println(list);
list.push("www");
System.out.println(list);
list.pop();
System.out.println(list);
}
private static void show01() {
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");
System.out.print(list);
System.out.println();
list.addFirst("w");
list.addLast("d");
System.out.print(list);//[w, a, b, c, d]
System.out.println(list.getFirst());
System.out.println(list.getLast());
System.out.println("++++++++");
}
}
set集合
HashSet
package demo02;
import java.util.HashSet;
import java.util.Set;
/*
* set特点
* 1.不允许重复
* 2.没有索引,普通for循环不能使用
* HashSet类特点:
1.不允许存储重复的元素
2.没有索引,也没有带索引的方法,也不能使用普通for循环
3.是个无序的集合,存储和取出元素的顺序可能不同
4.底层是-一个哈希表(查询速度非常快)
*/
public class SetTest01 {
public static void main(String[] args) {
Set<Integer> list = new HashSet<>();
list.add(1);
list.add(2);
list.add(1);
list.add(3);
for (Integer integer : list) {
System.out.println(integer);
}
Set<String> list1 = new HashSet<>();
String a1 = new String("abc");
//set1集合调用add方法的时候会自动调用元素的hashCode() equals()方法,判断元素是否重复
String a2 = new String("abc");
list1.add(a1);
list1.add(a2);
list1.add("重地");
list1.add("通话");
list1.add(a1);
System.out.println(a1.hashCode());//96354
System.out.println(a2.hashCode());//96354
System.out.println("重地".hashCode());//1179395
System.out.println("通话".hashCode());//1179395
for (String s : list1) {
System.out.println(s);//重地通话abc
}
}
}
哈希表
哈希冲突
当哈希值是一样的时候时会出现哈希冲突,这时候调用equals方法判断是否是true如果是true,那么就不会加入集合,如果是false那么会加入集合。
HashSet存储自定义元素类型:
要求:自定义类需要重写hashCode equals方法
import java.util.HashSet;
public class SetTest02 {
public static void main(String[] args) {
HashSet<Person> list = new HashSet<>();
list.add(new Person("大",8));
list.add(new Person("大",18));
list.add(new Person("大",8));
/*没有重写hashcode之前
* [Person{name='大', age=18}, Person{name='大', age=8}, Person{name='大', age=8}]*/
System.out.println(list);
/*重写之后
* [Person{name='大', age=18}, Person{name='大', age=8}]*/
}
}
import java.util.Objects;
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
LinkedHashSet:
LinkedHashSet:特点:
底层是哈希表(数组+链表+红黑树) +链表:
多了一条链表是用来记录元素的存储顺序的
保证元素有序
元素不能重复
import java.util.LinkedHashSet;
public class SetTest03 {
public static void main(String[] args) {
LinkedHashSet<String> list = new LinkedHashSet<>();
list.add("中");
list.add("大");
list.add("小");
list.add("钱");
list.add("中");
/*for (String s : list) {
System.out.println(s);
}*/
System.out.println(list);
}
}
可变参数
可变参数:是JDK1. 5之后出现的新特性
使用前提:当方法的参数列表中数据类型已经确定, 但是参数个数不确定,就可以使用可变参数
使用格式:定义方法时使用
修饰符返回值方法名(数据类型…变量名) {
可变参数底层就是个数组
注意事项:
1)一一个方法的参数列表只能有一-个可变参数
2)如果参数列表的参数有多个,那么可变参数一-定要写在末尾
package demo03;
/*
* 可变参数:是JDK1. 5之后出现的新特性
使用前提:当方法的参数列表中数据类型已经确定, 但是参数个数不确定,就可以使用可变参数
使用格式:定义方法时使用
修饰符返回值方法名(数据类型...变量名) {
可变参数底层就是个数组
*
* 注意事项:
1)一一个方法的参数列表只能有一-个可变参数
2)如果参数列表的参数有多个,那么可变参数一-定要写在末尾
* */
public class VarArgsTest {
public static void main(String[] args) {
int sum = add(1, 3, 6, 5, 9, 5, 1);
System.out.println(sum);
String s = add1("xuancheng", 1, 3, 6, 5, 9, 5, 1);
System.out.println(s);
}
public static String add1(String n,int...arr) {
int sum=0;
for (int i : arr) {
sum+=i;
}
return sum+n;
}
public static int add(int...arr) {
int sum=0;
for (int i : arr) {
sum+=i;
}
return sum;
}
}
Collections
Collections:
public static <T extends Comparable<? super T>> void sort(List list) 按照升序排列指定的列表
前提:被排序的集合里边存储的元素,必须实现Comparable接口,并且重写接口中CompareTo()方法
定义比较规则:
return this. age-o. age;//升序
return o. age-this. age;//降序
import java.util.ArrayList;
import java.util.Collections;
import demo02.Person;
import java.util.ArrayList;
import java.util.Collections;
/*Collections:
public static <T> boolean addALl(Collection<? super T> c, T... elements) 将所有指定的元素添加到指定的集合。
public证static void shuffle(List<?> list) 使用默认的随机源随机排列指定的列表
*/
public class CollectionsTest01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d");
System.out.println(list);//[a, b, c, d]
Collections.shuffle(list);
System.out.println(list);//[b, a, c, d]
ArrayList<Person> list1 = new ArrayList<>();
Collections.addAll(list1,new Person("战士",18),new Person("李四",20));
Collections.sort(list1);
System.out.println(list1);
}
}
import java.util.Objects;
public class Person implements Comparable<Person> {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person o) {
return this.age-o.age;//升序
//o.age-this.age//逆序
}
}