进阶Day03

Day03

第一章 数据结构

1.1 了解数据结构的作用

​ 了解数据结构有利于理解我们所使用工具的特点,明白它的底层原理,面对问题的时候选择一个合适的工具。

1.2 常见数据结构举例

栈:stack

栈是一种运算受限的线性表,限制在于:仅允许在标的一端进行插入和删除操作。

特点:

  • 进栈与出栈都在栈的顶端
  • 先进先出,后进后出,类似于一个放饼干的罐子,先放进去的饼干在最后才能拿出来。

在这里插入图片描述

两个名词

  • 压栈:元素存入栈中
  • 弹栈:从栈顶取出一个元素
队列:queue

同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。

采用该结构的集合有以下特点:

  • 先进先出
  • 出口入口各占一侧在这里插入图片描述
数组:Array

有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。每个元素有固定的编号。

特点:

  • 查找元素快 因为开辟的空间是连续的有固定的编号,根据编号索引
  • 增删元素慢
    在这里插入图片描述
    指定索引位置增加元素:

新建一个新数组,先将新元素添加在数组的末尾,再建一个新数组,把新元素填在指定位置,再复制原数组的元素。
在这里插入图片描述

指定索引位置删除:

在这里插入图片描述

所以增删不方便的原因是,要创建新数组,不能直接增减。

链表:Linked list

​ 由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动态生成,每个节点由数据域和指针域,指针域指向下一个数据域的地址。

采用该结构的集合,对元素的存取有如下的特点:

  • 查找元素慢,需要通过节点连接依次查找
  • 增删元素快,增时不需要创建新表,直接修改对应的节点和前一个指针的指向,并使新节点的指针域指向原来下一个节点。删除则移除那个节点,使节点前一个指针域直接指向后一个数据域。
    • 增:
    • 在这里插入图片描述
    • 减:
    • 在这里插入图片描述
二叉树:binary tree

是每个结点不超过2的有序树(tree),二叉树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”。
在这里插入图片描述

红黑树
  1. 节点可以是红色的或者黑色的
  2. 根节点是黑色的
  3. 叶子节点(特指空节点)是黑色的
  4. 每个红色节点的子节点都是黑色的
  5. 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同

红黑树的特点:

​ 速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍

第二章 List集合

1.1LIst接口的特点

  • 是一个元素存取有序的集合,元素在集合中的存储顺序与存入顺序一致
  • 可以通过索引获得指定元素
  • 集合中可以有重复的元素,是否重复采用元素的equals方法判断,比如说自定义一个类,默认是比较地址,可以根据自己需求改写equals方法。
常用方法
  • 添加元素 public void add(int index,E element)
  • 删除元素public E remove(int index)返回被删除的元素
  • 查询元素 public E get(int index)返回被索引的元素
  • 替换(设定值)public E set(int index,E element)返回被替换前的index处的元素。

需要注意的是,对于添加元素,还存在默认方法,加在集合的尾部。而使用指定位置添加元素时,要保证在这个位置上已经有元素存在,否则会报错。

第三章 List子类

3.1 ArrayList

java.util.ArrayList集合数据存储的结构是数组结构。具有数组结构增删慢,查找快的特点。最常用的应用功能是查找、边里、但在解决问题过程中不能盲目使用。

3.2 LinkedList

java.util.LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。

LinkedList是一个双向链表,结构如下图所示
在这里插入图片描述

它与之前介绍的单向链表有所不同,单向链表只有一个指针域,双向有两个,单向只能知道自己后面一个元素,双向前后都能知道。

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。

  • public void addFirst(E e)将元素插入表头

  • public void addLast(E e)插入表尾

  • public E getFrist()得到表中第一个元素(最后一个同理)

  • public E removeFirst()移除第一个元素,并返回被移除的元素

  • public E pop() 弹出此表表示的栈中栈顶元素,之后栈中不存在钙元素

  • public void push(E e)将一个元素压入该表表示的堆栈、

  • public boolean isEmpty()判断是否包含元素

    public static void main(String[] args)  {
    		LinkedList linklist = new LinkedList();
    		linklist.add(55);
    		linklist.add(66);
    		linklist.add(77);
    		System.out.println(linklist);// [55,66,77]
    		System.out.println(linklist.pop());//弹出栈顶元素55
    		System.out.println(linklist);//[66,77]
    		linklist.push(456789);//压入栈顶
    		System.out.println(linklist);[456789,66,77]
    		}
    

链表表示为堆栈的示意图:类似于一个“转置”的过程
在这里插入图片描述

第四章 Set接口

java.util.Set接口和java.util.List接口一样,同样继承自Collection接口。Set接口相比于Collection接口没有功能扩充,但是要求更加严格,不能有重复的元素存在,是否重复根据hashCode和equals来判断。与List接口相比,Set接口中的元素时无序的。

4.1 HashSet集合

HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。

public static void main(String[] args)  {
		HashSet set = new HashSet();
		set.add(123);
		set.add(9);
		set.add(123);
		set.add("sdasdsa");
		set.add(6);
		System.out.println(set);//[sdasdsa, 6, 9, 123],重复的元素无法再次存入
		}

4.2 HashSet中的数据结构

JDK1.8之前,哈希表底层采用数组+链表实现,链表长度过长时即hash值相等的元素较多时,通过key值依次查找的效率较低,会影响查询效率。

在这里插入图片描述
JDK1.8中,哈希表存储采用数组+链表+红黑树实现。链表长度>阈值8时,会自动转换成红黑树,减少查询时间。
在这里插入图片描述

4.3 HashSet存储自定义类型元素

“如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。”

import java.util.HashSet;
import java.util.Objects;
public class test {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet set= new HashSet();
		set.add(new Student("first",18));
		set.add(new Student("second",19));
		set.add(new Student("third",20));
		set.add(new Student("fourth",21));
		set.add(new Student("fourth",25));
		set.add(new Student("first",25));
		set.add(new Student("first",18));
		set.add(new Student("Last",18));
		System.out.println(set);
        //[first 25, Last 18, third 20, fourth 21, first 18, fourth 25, second 19]
	}
}
class Student{
	private String name;
	private Integer age;	
	public Student(String name, Integer age) {
		this.name = name;
		this.age = age;
	}
	@Override
	public boolean equals(Object o) {
		if(this == o) {
			return false;
		}
		if(o == null || o.getClass() != this.getClass()) {
			return false;
		}
		Student studenttemp = (Student)o;		
		return studenttemp.age == this.age && studenttemp.name==this.name;
	}
	@Override
	public int hashCode() {
		return Objects.hash(name,age);
	}
	@Override
	public String toString() {
		return name+" "+age;
	}
}

4.4 LinkedHashSet

java.util.LinkedHashSet是HashSet下面有一个子类,它是链表和哈希表组合的一个数据存储结构。它可以保证集合的有序。

public static void main(String[] args) {
		// TODO Auto-generated method stub
		LinkedHashSet<String> set = new LinkedHashSet<String>();
		set.add("aaa");
		set.add("bbb");
		set.add("ccc");
		set.add("aaa");
		set.add("ddd");
		Iterator it = set.iterator();
		while(it.hasNext()) {
			System.out.print(it.next()+" ");//aaa bbb ccc ddd
		}
	}

第五章 可变参数

JDK1.5之后,定义一个方法时,需要多个的同一类参数,可以简化成

修饰符 返回值类型 方法名(参数类型... 参数名){方法体}

它等价于修饰符 返回值类型 方法名(参数类型[] 参数名){方法体},...称为可变参数

区别第二种定义时,只能传递数组,而前者可以直接传递数据,在编译时会自动封装成数组,在调用时就不用手动创建数组(更加方便)。

其实编译成的class文件,将这些元素先封装到一个数组中,在进行传递。这些动作都在编译.class文件时,自动完成了。

public static void main(String[] args) {
		int [] arr = {1,2,3,4,5,6,7,8,9};
		System.out.println(getSum(arr));//45
		System.out.println(getSum(1,2,3,4,5,6,7,8,9));//45
		}	
	public static Integer getSum(int... a) {
		int returnsum=0;
		for(int b: a) {
			returnsum+=b;
		}
		return returnsum;
	}

上述add方法在同一个类中,只能存在一个。因为会发生调用的不确定性。

方法的参数中含有可变参数时,可变参数必须要放在参数列表的最后一个。

第六章 Collections

6.1 常用功能

  • 增加一系列元素public boolean addAll(Collection<T>,T... Elements)

  • 打乱顺序public static void shuffle(List<?> list)

  • public static <T> sort(List<?> list)将集合中元素按照默认规则排序,如数字默认为按大小升序排列

  • public static <T> sort(List<?> list,Comparator<? super T>)将集合中的元素按照用户自定义的规则排序,如将数字进行降序排列

    public class test {
    	public static void main(String[] args) {
    		ArrayList<Integer> list = new ArrayList<Integer>();
    		Collections.addAll(list, 5,6,7,8,9,10);
    		Collections.shuffle(list);
    		System.out.println(list);
    		Collections.sort(list);
    		System.out.println(list);
    		Collections.sort(list, new Comparator<Integer>() {
    			@Override
    			public int compare(Integer o1, Integer o2) {
    				return o2-o1;//降序排列
    			}
    		});
    		System.out.println(list);
    	}
    	}
    

6.2 Comparator比较器

那么在JAVA中提供了两种比较实现的方式,一种是比较死板的采用java.lang.Comparable接口去实现,一种是灵活的当我需要做排序的时候在去选择的java.util.Comparator接口完成。

如果使用public <T> void sort(List<?> list)进行比较时,含义是已经实现了Compareble接口。例如String类中就已经实现了这一接口,所以可以直接调用此方法进行比较,但是它的缺点是,规则已经定死,如果想进行逆序排列或者其他规则,则要重写此方法。

这种情况下可以采用public <T> void sort(List<T> list,Comparator<? extends T>)的方式,通过实现public int compare(E e1,E e2)来灵活确定规则。

两个对象比较的结果有三种:大于,等于,小于。

如果要按照升序排序,
则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数)
如果要按照降序排序
则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)

简单来说就是,若想升序则return o1-o2;反之是o2-o1;

6.3 Comparator接口与Comparable接口的区别

Comparable接口在使用前需要在类中重写方法,对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,重写后可以直接调用public <T> void sort(List<?> list)进行比较,无需指定比较器,缺点是规则一旦确定修改比较麻烦。

Comparator 接口在使用定义Compare比较器,根据自身需求以及没有自然顺序的对象Collection设定规则,使用灵活,但是每次都要定义,如果需要多次比较且规则单一,还是Comparable比较方便。

6.4 练习

创建一个学生类,存储到ArrayList集合中完成指定排序操作。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class test {
	public static void main(String[] args) {
		ArrayList<Student> list = new ArrayList<Student>();
		list.add(new Student("cbx",20));
		list.add(new Student("aby",19));
		list.add(new Student("bbz",18));
		Collections.sort(list, new Comparator<Student>() {
			@Override
			public int compare(Student o1, Student o2) {
				return o1.getAge()-o2.getAge();
			}	
		});//按照年龄升序排列
		System.out.println(list);
		Collections.sort(list, new Comparator<Student>() {
			@Override
			public int compare(Student o1, Student o2) {
				// TODO Auto-generated method stub
				return o2.getName().charAt(2)-o2.getName().charAt(2);
			}	
		});//按照姓名最后一个字母降序排列
		System.out.println(list);
	}
	}
class Student{
	private String name;
	private Integer age;
	public Student(String name, Integer age) {
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "姓名:"+name+" "+"年龄:"+age;
	}
	public String getName() {
		return name;
	}
	public Integer getAge() {
		return age;
	}
}

输出结果:

[姓名:bbz 年龄:18, 姓名:aby 年龄:19, 姓名:cbx 年龄:20]
[姓名:bbz 年龄:18, 姓名:aby 年龄:19, 姓名:cbx 年龄:20]

上述方式是采用Comparator接口的方式。

Comparable接口方式:

需要修改Student类中的内容

public class test {
	public static void main(String[] args) {
		//学生类创建内容与先前保持一致
		Collections.sort(list);
		System.out.println(list);//[姓名:cbx 年龄:20, 姓名:aby 年龄:19, 姓名:bbz 年龄:18]
	}
	}
class Student implements Comparable<Student>{
	...
	@Override
	public int compareTo(Student o) {
		
		return o.age-this.age;
	}//以年龄为比较降序排列
	
}

拓展:

//还可以进一步定义规则
...
Collections.sort(list, new Comparator<Student>() {
			@Override
			public int compare(Student o1, Student o2) {
				if(o1.getAge() != o2.getAge()){
                return o1.getAge()-o2.getAge();}
                else{
      return o1.getName().cahrAt(0)-o2.getName().cahrAt(0);
                }
			}	
		});
...
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值