尝试纯手写java集合类

尝试纯手写java集合类

之前学习java集合类,留下了很多问题,最不明白Node是什么?为什么需要使用它?现在我终于懂了!

Node节点的重要性

  • 每一个链表实际上就是有多个节点所组成,链表就好比火车,都是有一节一节的车厢组成,每一节车厢,既可以载乘客,也提示了下一节车厢和上一节车厢的信息,这就好比是Node,不仅仅是为了保存数据,也是为了保存下/上一个节点的信息,另外,保存的数据,没有办法保存下一个节点的信息,就单单是一个数据,同时,数据的保存,也需要一个包装类来保存。这个时候,Node的重要性就脱颖而出了。可以参考一下代码来思考:
package com.node;
/**
 * @param
 * @author qzp
 * @create 2020-03-21 0:48
 */
//每一个链表实际上就是有多个节点所组成
class Node {//定义一个节点
    private String data;//要保存的数据
    private Node next;//要保存的下一个节点
    //每一个Node类对象都要保存有相应的数据
    public Node(String data) {//必须有数据才能Node
        this.data = data;
    }
    public void setNext(Node next){
        this.next = next;
    }
    public Node getNext(){
        return this.next;
    }
    public String getData(){
        return this.data;
    }
}
class LinkDemo{
    public static void main(String[] args) {
        //第一步,准备取出所有数据
        Node root = new Node("火车头");
        Node s1 = new Node("车厢A");
        Node s2 = new Node("车厢B");
        root.setNext(s1);
        s1.setNext(s2);
        test(root);
       /* System.out.println(root.getData());
        System.out.println(s1.getData());
        System.out.println(s2.getData());*/
    }
    public static  void test(Node node){
        if(node == null){
            return;
        }
        System.out.println(node.getData());
        test(node.getNext());
    }
}

1.手写代码实现ArrayList集合

package com.mage;
/**
 * @param
 * @author qzp
 * @create 2020-03-20 21:48
 */
public class MyArrayList {
    //存储数据的数组
    private Object[] elementDate;
    //存储数据的个数
    private int size;
    //数组的长度
    private static final int DEFAULT_CAPACITY=10;

    public MyArrayList() {
        elementDate = new Object[DEFAULT_CAPACITY];
    }
    //数据超过默认值时
    public MyArrayList(int capacity) {
        if(capacity<0){
            throw new RuntimeException("容器的容量不能设为负值");
        }else if(capacity==0){
            elementDate = new Object[DEFAULT_CAPACITY];
        }else {
            elementDate = new Object[capacity];
        }
    }
    /**
     * 返回list大小 size()
     * 返回SxtArrayList对象大小即SxtArrayList中数组大小
     */
    public int size(){
        return size;
    }
    /**
     * 判断list是否为空 isEmpty() 此方法待改进 初始化时并未使用size 只有add时候用到size属性 直接判断size不正确
     * 返回SxtArrayList对象是否为空即SxtArrayList中数组中是否有实际值
     */
    public boolean isEmpty(){
        return size == 0;
    }
    /**
     * 删除指定位置对象 remove(int index)
     * rangeCheck(index)检验数组下标是否越界
     * 删除对象前计算出要删除的对象后面还剩多少对象以便于后面元素向前移动
     * 移动对象
     * 原数组最后一位设置为空
     * 如果删除对象在数组最后一位则直接删除无需数组元素移动
     * 返回 null
     */
    public void remove(int index){
        rangeCheck(index);
        int numMove = size - index -1;
        if(numMove > 0) {
            //第一个是要复制的数组,第二个是从要复制的数组的第几个开始,
            //第三个是复制到那,四个是复制到的数组第几个开始,最后一个是复制长度
            System.arraycopy(elementDate, index + 1, elementDate, index, numMove);
        }
        elementDate[--size] = null;
    }
    /**
     * 删除指定对象 remove(Object obj)
     * 判断传入对象是否存在
     * 如果存在则会得到相应下标位置
     * 利用下标位置删除此元素
     * 返回 null
     */
    public void remove(Object obj){
        for(int i=0;i<size;i++){
            if(getIndex(i).equals(obj)){//底层是equls
                remove(i);
            }
        }
    }

    //添加数据
    private void add(Object object){
        //扩容
        if(size==elementDate.length){
            Object[] newArray = new Object[elementDate.length+(elementDate.length>>1)];
            System.arraycopy(elementDate,0,newArray,0,elementDate.length);
            elementDate = newArray;
        }
        elementDate[size++] = object;
    }
    //根据索引取值
    public Object getIndex(int index){
        rangeCheck(index);
        return elementDate[index];
    }
    //根据索引修改值
    public void setIndex(int index,Object object){
        //检查索引
        rangeCheck(index);
        elementDate[index]=object;
    }
    /**
     * 检验数组下标是否越界
     */
    private void rangeCheck(int index){
        if(index<0 || index>=size){
            try {
                throw new Exception("下标越界");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(elementDate[i]+",");
        }
        sb.setCharAt(sb.length()-1,']');
        return sb.toString();
    }

    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add("abc");
        System.out.println(myArrayList);
        for (int i = 0; i < 40; i++) {
            myArrayList.add("gao"+i);
        }
        System.out.println(myArrayList);
        final Object index = myArrayList.getIndex(10);
        System.out.println(index);
        System.out.println(myArrayList.size);
        myArrayList.setIndex(1,"你好");
        System.out.println(myArrayList);
        myArrayList.remove(2);
        System.out.println(myArrayList);
        myArrayList.remove("gao4");
        System.out.println(myArrayList);
    }
}

2.手写代码实现LickedList集合

package com.mage;
import java.util.Map;
/**
 * @param
 * @author qzp
 * @create 2020-03-20 23:18
 */
public class Node {
    Node previous;//前一个节点
    Node next;//下一个节点
    Object element;//本节点保存的值

    public Node(Node previous, Node next, Object element) {
        this.previous = previous;
        this.next = next;
        this.element = element;
    }

    public Node(Object element) {
        this.element = element;
    }
}


package com.mage;
/**
 * @param
 * @author qzp
 * @create 2020-03-20 23:16
 */
public class MyLickedList {
    private Node first;//第一个节点
    private Node last;//最后一个节点
    private int size;//当前节点个数

    //增加节点
    private void add(Object object){
        Node node = new Node(object);
        if(first == null){
            node.previous = null;
            node.next = null;
            first = node;
            last = node;
        }else {
            node.previous = last;
            node.next = null;
            last.next = node;
            last = node;
        }
        size++;
    }
    //删除节点值,先要通过索引来查出节点
    public void remove(int index){
        Node temp = getNode(index);
        if(temp != null){
            Node up = temp.previous;
            Node down = temp.next  ;
            if(up !=null){
                up.next = down;
            }
            if (down !=null){
                down.previous = up;
            }
            //被删除第一个节点
            if(index == 0){
                first = down;
            }
            //被删除最后一个节点
            if(index == size-1){
                last = up;
            }
            size--;
        }
    }
    //插入节点
    public void insert(int index,Object object){
        Node newNode = new Node(object);
        Node temp = getNode(index);
        if(temp != null){
            Node up = temp.previous;
            if(up !=null){
                up.next = newNode;
                newNode.previous = up;
                newNode.next = temp;
                temp.previous = newNode;
            }
            size++;
        }
    }
    //根据indes来获取节点
    public Node getNode(int index){
        if(index<0||index>size-1){
            throw new RuntimeException("索引不合法");
        }
        Node temp = null;
        if(index<=(size>>1)){
           temp = first;
            for (int i = 0; i < index; i++) {
                temp = temp.next;
            }
            return temp;
        }else{
           temp = last;
            for (int i = size-1; i > index; i--) {
                temp = temp.previous;
            }
            return temp;
        }
    }
    //获取节点值
    public Object get(int index){
        Node temp = getNode(index);
        /*if(index>(size>>1)){
            Node temp = first;
            for (int i = 0; i < index; i++) {
                temp = temp.next;
            }
            return temp.element;
        }else{
            Node temp = last;
            for (int i = 0; i > index; i--) {
                temp = temp.previous;
            }*/
            return temp!=null?temp.element:null;
    }
    public int size(){
        /*
         * 返回数据对象的个数
         */
        return size;
    }
    //返回节点的所有元素值
    public Object[] toArray(){
        Object[] temp = new Object[size];
        Node node = first;
        for(int i = 0;i < size;i++){
            temp[i] = node.element;
            node = node.next;
        }
        return temp;
    }
    //打印
    @Override
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        Node temp = first;
        while (temp != null){
            sb.append(temp.element+",");
            temp = temp.next;
        }
       sb.setCharAt(sb.length()-1,']');
        return sb.toString();
    }
    public static void main(String[] args) {
        MyLickedList myLickedList = new MyLickedList();
        myLickedList.add("a");
        myLickedList.add("b");
        myLickedList.add("c");
        myLickedList.add("d");
        myLickedList.add("e");
        myLickedList.add("f");
       /* System.out.println(myLickedList);
        System.out.println(myLickedList.get(4));
        myLickedList.remove(0);
        System.out.println(myLickedList);
        myLickedList.remove(4);
        System.out.println(myLickedList);*/
       Object[] all = myLickedList.toArray();
        for (int i = 0; i < all.length; i++) {
            Object o = all[i];
            System.out.print(o+",");
        }
    }
}

3.手写代码实现HashMap集合

package com.map;

/**
 * @param
 * @author qzp
 * @create 2020-03-21 15:17
 */
//用于MyHashMap中
public class Node {
    int hash;
    Object key;
    Object value;
    Node next;

    public Node() {
    }

    public Node(int hash, Object key, Object value, Node next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }
}

package com.map;
import java.util.HashSet;
import java.util.Set;

/**
 * @param
 * @author qzp
 * @create 2020-03-21 15:16
 */
public class MyHashMap {
    Node[] table;//位桶数组
    int size;//存放的键值对的个数

    public MyHashMap() {
        table = new Node[16];//长度是默认的,一般是2的整数幂
    }

    //计算hsah值
    public int myHash(int v,int length){
        System.out.println("方式一计算hash"+v%length);
        System.out.println("方式二:"+(v&(length-1)));
        return v&(length-1);
    }

    //添加
    public void put(Object key,Object value){
        //定义新的节点
        Node newNode = new Node();
        newNode.hash = myHash(key.hashCode(),table.length);
        newNode.key=key;
        newNode.value=value;
        newNode.next=null;

        Node temp = table[newNode.hash];
        Node iterLast = null;//正在遍历的最后一个元素
        boolean keyRepeat = false;
        //判断数组中元素是否为空,为空,则直接将新节点放进去
        if(temp==null){
            table[newNode.hash] = newNode;
            size++;
        }else{
            //此处数组不为空,则需要遍历对应的单链表
            while (temp !=null){
                //判断key如果重复,则进行覆盖
                if(temp.key.equals(key)){
                    System.out.println("key重复了");
                    temp.value = value;
                    keyRepeat = true;
                    break;
                }else {
                    //key值不重复,则遍历下一个
                    iterLast = temp;
                    temp=temp.next;
                }
            }
            //添加节点到链表的最后一个
            if(!keyRepeat & iterLast != null){
                iterLast.next = newNode;
                size++;
            }
        }
    }

    //添加get方法获取value
    public Object get(Object key){
        int hash = myHash(key.hashCode(),table.length);
        Object value = null;
        if(table[hash]!=null){
            Node temp = table[hash];
            while (temp != null){
                if(temp.key.equals(key)){
                    value = temp.value;
                    break;
                }else {
                    temp = temp.next;
                }
            }
        }
        return value;
    }

    //重写tostring方法
    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        for (int i = 0; i < table.length; i++) {
            Node node = table[i];
            while (node !=null){
                sb.append(node.key+":"+node.value+",");
                node = node.next;
            }
        }
        sb.setCharAt(sb.length()-1,']');
       return sb.toString();
    }

    public static void main(String[] args) {
        MyHashMap myHashMap = new MyHashMap();
        myHashMap.put(10,"aa");
        myHashMap.put(20,"bb");
        myHashMap.put(30,"cc");
        myHashMap.put(30,"mm");
        myHashMap.put(53,"bb");
        myHashMap.put(69,"cc");
        myHashMap.put(85,"mm");
        System.out.println(myHashMap);
        System.out.println(myHashMap.get(85));
        final Set<String> strings = new HashSet<>();
    }
}

4.手写代码实现HashSet集合

package com.set;

import java.util.HashMap;

/**
 * @param
 * @author qzp
 * @create 2020-03-22 17:33
 */
public class MyHashSet {
    HashMap map;

    private static final Object PRESENT = new Object();

    public MyHashSet() {
        map = new HashMap();
    }
    public int size(){
        return map.size();
    }
    public void add(Object object){
        map.put(object,PRESENT);
    }
    @Override
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        for (Object o : map.keySet()) {
            sb.append(o+",");
        }
        sb.setCharAt(sb.length()-1,']');
        return sb.toString();
    }

    public static void main(String[] args) {
        final MyHashSet myHashSet = new MyHashSet();
        myHashSet.add("aa");
        myHashSet.add("bb");
        myHashSet.add("cc");
        System.out.println(myHashSet);
    }
}

你可能感兴趣的:(java学习笔记)