面试BAT过后,终于开始整理容器。

JAVA容器,爱并恨着。

对于校招生,容器部分以下应该够你用了。加油吧,骚年。
对于JAVA容器简单分类如下图:
红色:表示接口
在这里插入图片描述容器顾名思义就是为了装东西JAVA而提供的一个解决方法。
说到存储,很多人会想到数组。

选择容器而不是数组的原因:

数组:
长度必须在初始化时指定,且固定不变
数组缺乏封装,操作繁琐
数组无法直接保存映射关系
数组采用连续存储空间,删除和添加效率低下

整体集合架构

Collection 接口存储一组不唯一,无序的对象
List 接口存储一组不唯一,有序(索引顺序)的对象
Set 接口存储一组唯一,无序的对象
Map接口存储一组键值对象,提供key到value的映射 (其中key唯一无 序,value不唯一,无序。)

List(ArrayList,LinkedList)

List 特点:有序 不唯一(可重复

ArrayList:线性表中的顺序表

特点:在内存中分配了连续空间,实现了长度可变的数组。
优点:遍历元素和随机访问元素的效率较高
缺点:添加和删除需大量移动元素效率低,按照内容查询效率低

手写ArrayList

package com.lidadaibiao.ArrayList;

import javax.management.RuntimeErrorException;

import org.w3c.dom.ranges.RangeException;

/**
 * 
 * @author 李大代表
 *
 */
public class DongArrayList5 {
	public static void main(String[] args) {
		ArrayList5<String> arr = new ArrayList5<String>(20);
		//System.out.println("测试数组扩容---------------");
		/*for(int i = 0;i<30;i++){
			arr.add("代表");
		}*/
		for(int i = 0;i<30;i++){
			arr.add(""+i);
		}
		System.out.println("数组删除");
		arr.remove(2);
		arr.remove("7");
		System.out.println(arr.toString());
	/*	System.out.println(arr.toString());
		System.out.println("-----get/set/索引越界问题------");
		arr.set("兵长",10);
		System.out.println(arr.toString());
		String string = arr.get(10);
		System.out.println(string);
		arr.set("dd",50);*/
		
		/*arrayList1.add("aa");
		arrayList1.add("aa1");
		String object = arrayList1.get(0);
		System.out.println(object);
		String object1 = arrayList1.get(1);
		String object2 = arrayList1.get(2);
		String object3 = arrayList1.get(3);
		System.out.println(object1);
		System.out.println(object2);
		System.out.println(object3);
		System.out.println("----------");
		System.out.println(arrayList1.toString());*/
	}
}
class ArrayList5<E>{
	private Object[] elementData;
	private int size;
	private static final int DEFALT_CAPACITY=10;
	public ArrayList5(){
		elementData = new Object[DEFALT_CAPACITY];
	}
	
	
	public ArrayList5(int size){
		if(size<0){
			throw new RuntimeException("容器容量范围>=0");
		}else if(size == 0){
			elementData = new Object[DEFALT_CAPACITY];
		}else{
			elementData = new Object[size];
		}
		
	}
	
	public void checkRange(int index){
		//判断索引是否合法
				if(index<0||index>=size){
					throw new RuntimeException("索引不合法:"+index);
				}
	}
	public void add(E e){
		//开始扩容 判断是否到达最大值
		if(size == elementData.length){
			//如果到达容器最大值则扩容
			//新建一个数组
			//elementData.length+(elementData.length>>1)括号的原因是因为+号优先级比>>大
			Object[] newelementData = new Object[elementData.length+(elementData.length>>1)];
			//将老数组中的元素拷贝进入新数组中
			System.arraycopy(elementData, 0,newelementData,0,elementData.length);
			//将新数组的内存地址赋给老数组
			elementData = newelementData;
		}
		elementData[size++] = e;
	}
	public E get(int size){
		checkRange(size);
		return  (E)elementData[size];
	}
	public void set(E e,int index){
		checkRange(index);
		elementData[index] = e;
	}
	//按照元素进行删除元素  理论上都是移除,因为内存中并不会删除该元素
	public void remove(E e){
		//循环查找需要移除的元素
		for(int i = 0 ; i<size;i++){
			
			if(e.equals(get(i))){
				remove(i);
			}
		}
	}
	//按照索引进行删除元素
	public void remove(int index){
		int num = elementData.length-index-1;
		//判断的原因是防止删除的是最后一个
		if(num>0){
		System.arraycopy(elementData, index+1, elementData, index,num);
  		}
		elementData[--size]=null;
		
	}
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		for(int i = 0;i<size;i++){
			sb.append(elementData[i]+",");
		}
		sb.setCharAt(sb.length()-1,'}');
		return sb.toString();
	}
}

LinkedList 线性表中双向链表

特点: 采用双向链表存储方式
优点:插入、删除元素效率比较高(但是前提也是必须先低效率查询才可。如果插入删除发 生在头尾可以减少查询次数)
缺点:遍历和随机访问元素效率低下。
手写LinkedList

package com.lidadaibiao.LinkedList;
/**
 * 李大代表
 * @author ASUS
 *
 *
 */
public class DongLinkedList2 <E>{
	private int size;//定义大小
	private Node frist;//定义首节点
	private Node last;//定义终结点
	
	
	public void checkRange(int index){
		if(index<0 || index>size){
			throw new RuntimeException("索引不合法:"+index);
		}
	}
	public void add(int index,E obj){
		Node newNode = new Node(obj);
		Node temp = getNode(index);
		if(temp!=null){
			Node up = temp.privious;
			
			up.next = newNode;
			newNode.privious = up;
			
			newNode.next = temp;
			temp.privious = newNode;
			
		}
	}
	//根据索引删除一个值
	public void remove(int index){
		Node temp = getNode(index);
		//先判断是否为空
		if(temp!=null){
			Node up = temp.privious;
			Node down = temp.next;
			if(up!=null)
			{
			up.next = down;
			}
			if(down!=null)
			{
			down.privious = up;
			}
			if(index==0){
				frist = down;
			}
			if(index==size-1){
				//last = up;
				last = null;
			}
			size--;
		}
	}
	//根据索引get一个值
	public E get(int index){
		
		return (E)getNode(index).element;
	
	}
	//得到一个node
	private   Node getNode(int index){
		Node temp ;
		checkRange(index);
		if(index<(size>>1)){//>>1 相当于除以2
			temp = frist;
		for(int i = 0;i<index;i++){//小于一半 向后找
			temp =temp.next;
			
		}
	
		}
		else{
			temp = last;
			for(int i = size;i>index;i--){//大于一半 从后向前找
				temp = temp.privious;
			}
		}	
		return temp;
	}
	//打印
	public String toString(){
		Node temp = frist;
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		while(temp!=null){
			sb.append(temp.element+",");
			temp = temp.next;
		}
		sb.setCharAt(sb.length()-1,'}');
		return sb.toString();
	}
	public void add(Object obj){
		Node node = new Node(obj);//创建一个节点 并赋值
		//判断是否为首节点
		if(frist==null){
			frist = node;
			last = node;
		}
		else{
			node.privious=last;
			node.next = null;
			last.next = node;
			last = node;
		}
		size++;
	}
	public static void main(String[] args) {
		DongLinkedList2 dongLinkedList = new DongLinkedList2();
		dongLinkedList.add("1");
		dongLinkedList.add("2");
		dongLinkedList.add("3");
		dongLinkedList.add("4");
		dongLinkedList.add("5");
		System.out.println(dongLinkedList.toString());
		/*System.out.println(dongLinkedList.get(0));
		dongLinkedList.remove(5);
		dongLinkedList.remove(0);
		System.out.println(dongLinkedList.toString());*/
		dongLinkedList.add(2,"22");
		System.out.println(dongLinkedList.toString());
		
	}
}
class Node {
	public Node privious;
	public Node next;
	public Object element;
	public Node() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Node(Node privious, Node next, Object element) {
		super();
		this.privious = privious;
		this.next = next;
		this.element = element;
	}
	public Node(Object element) {
		super();
		this.element = element;
	}
	public Node getPrivious() {
		return privious;
	}
	public void setPrivious(Node privious) {
		this.privious = privious;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
	public Object getElement() {
		return element;
	}
	public void setElement(Object element) {
		this.element = element;
	}
	
}

Set(HashSet,TreeSet)

特点:无序并唯一

HashSet

特点:采用哈希表存储结构
优点: 添加,删除,查询速度快。
缺点:无序。
手写HashSet

package com.lidadaibiao.hashSet;

import java.util.HashMap;
import java.util.Map;
/**
 * 底层手写HashSet
 * @author ASUS
 * 无顺序 不重复
 *
 */
public class DoHashSet {
	public Map map;
	private static final Object PRESENT = new Object();
	public DoHashSet(){
		map = new HashMap();
	}
	public int size(){
		return map.size();
	}
	public String toString(){
		StringBuilder sb = new StringBuilder();
		
		sb.append("{");
		
		for (Object v : map.keySet()) {
			sb.append(v+",");
		}
		sb.setCharAt(sb.length()-1, '}');
		
		return sb.toString();
	}
	public void add(Object o){
		map.put(o, PRESENT);
	}
	public static void main(String[] args) {
		DoHashSet dset = new DoHashSet();
		dset.add("111");
		dset.add("222");
		dset.add("333");
		dset.add("444");
		dset.add("555");
		dset.add("111");
		System.out.println(dset.toString());
	}
}

TreeSet

特点:采用二叉树(红黑树)的存储结构
优点:有序 (内容)查询速度比List快
缺点:查询速度慢于HashSet

LinkedHashSet

特点如其名:采用哈希表存储结构,用链表维护次序,有序。

Map(HashMap,LinkedHashMap,TreeMap

特点:采用键值对映射。

HashMap

Key无序 唯一 采用 Set方式进行存储。
Value无序 不唯一 采用Collection方式进行存储。
手写HashMap

package com.lidadaibiao.hashMap;
/**
 * 自定义一个hashmap
 * 实现了put 方法增加键值对 并解决了键重复的时候覆盖相应的节点
 * 实现tostring 方法
 * 实现Get方法
 * 完善封装 增加泛型
 * @author ASUS
 *
 */
public class DoHashMap4<K,V> {
	public static void main(String[] args) {
		DoHashMap4<Integer,String> doHashMap = new DoHashMap4();
		doHashMap.put(10, "22");
	
		doHashMap.put(30, "33");
		doHashMap.put(40, "11");
		System.out.println(doHashMap.get(10));
	}
	
	
	
	
	Node2[] table;//位桶数组 bucket array
	int size;//存放的键值个数
	public DoHashMap4(){
		table = new Node2[16];//长度为2的整数幂
	}
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		for(int i = 0;i<table.length;i++){
			Node2 temp = table[i];
			while(temp!=null){
				sb.append("["+temp.key+","+temp.value+"]"+",");
				temp = temp.next;
			}
		}
		sb.setCharAt(sb.length()-1,'}');
		return sb.toString();
	
	}
	public V get(K key){
		int hash = myHash(key.hashCode(),table.length);
		V value = null;
		if(table[hash]!=null){
			Node2 temp = table[hash];
			while(temp!=null){
				if(temp.key.equals(key))
				{
				value = (V)temp.value;
				break;
				}
				else{
					temp = temp.next;
				}
			}
		}
		return value;
	}
	public void put(K key,V value){
		//定义一个新的节点
		Node2 newNode2 = new Node2();
		newNode2.hash = myHash(key.hashCode(),table.length);
		newNode2.key = key;
		newNode2.value = value;
		newNode2.next = null;
		
		Node2 temp = table[newNode2.hash];
		Node2 itrLast =null;//正在遍历的最后一个元素
		boolean flag = false;//是否发生重复的标志
		if(temp==null){
			//此处数组为空则直接将新节点放进去
			table[newNode2.hash] = newNode2;
			size++;
		}
		else{
			//此处数组不为空,则遍历链表
			while(temp!=null){
				if(temp.key.equals(key)){
					//如果存在重复
					flag = true;
					temp.value = value;
				
					break;
				}
				else{
					//如果不重复 遍历下一个
					itrLast = temp;
					temp = temp.next;
				
				}
			}
			if(!flag){
				itrLast.next = newNode2 ;
				size++;
			}
			
		}
	}
	private int myHash(int hashCode, int length) {
		// TODO Auto-generated method stub
/*		System.out.println("位运算"+(hashCode&(length-1)));
		System.out.println("模运算"+(hashCode%(length-1)));*/
		return hashCode&(length-1);
	}
	
}
class Node2<K,V> {
	int hash;
	Node2 next;
	K key;
	V value;
}

LinkedHashMap

特点;链表+哈希表,有序,速度快。

TreeMap

特点:红黑树,有序。

List Set Map 遍历方式

(Iterator迭代器的使用)

package com.lidadaibiao.list;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class IteratorTest {
	public static void main(String[] args) {
        System.out.println("list set map 遍历方式");
		IteratorTestList();
		System.out.println("-------------");
		IteratorTestSet();
		System.out.println("-------------");
		IteratorTestMap();

	}
	public static void IteratorTestList(){
		List<String> list = new ArrayList<String>();
		list.add("11");
		list.add("12");
		list.add("13");
		list.add("14");
	
		Iterator<String> iterator = list.iterator();
		while(iterator.hasNext()){
			String next = iterator.next();
			System.out.println(next);
		}
	}
	public static void IteratorTestSet(){
		Set<String> set = new HashSet<>();
		set.add("22");
		set.add("23");
		set.add("24");
		set.add("25");
		set.add("22");
		Iterator<String> iterator = set.iterator();
		while(iterator.hasNext()){
			String next = iterator.next();
			System.out.println(next);
		}
	}
	public static void IteratorTestMap(){
		Map<Integer,String> map = new HashMap<Integer, String>();
		map.put(1, "111");
		map.put(2, "22");
		map.put(3, "333");
		
		//方式1
		Set<Entry<Integer, String>> entrySet = map.entrySet();
		Iterator<Entry<Integer, String>> iterator = entrySet.iterator();
		while(iterator.hasNext()){
			Entry<Integer, String> next = iterator.next();
			System.out.println(next.getKey()+","+next.getValue());
		}
		//方式二
		Set<Integer> keySet = map.keySet();
		Iterator<Integer> iterator2 = keySet.iterator();
		while(iterator2.hasNext()){
			Integer key = iterator2.next();
			System.out.println(key+","+map.get(key));
		}
	}
}

几种容器比较
Vector(底层使用synchronized代码块锁 ) 和ArrayList
原理,功能,数据存储相同很多情况下可以互用。
不同:Vector线程安全,效率低下;ArrayList重速度轻安全,线程非安全
Hashtable(底层使用synchronized代码块锁 )和HashMap
原理,功能,底层都是哈希表结构,查询速度快,很多情况下可以互用。
不同:Hashtable继承Dictionary类,HashMap实现Map接口
Hashtable线程安全,HashMap线程非安全
Hashtable不允许null值,HashMap允许null值

小总结:在这里插入图片描述

发布了20 篇原创文章 · 获赞 17 · 访问量 1787

猜你喜欢

转载自blog.csdn.net/qq_42534991/article/details/105188238