0    课程地址

https://coding.imooc.com/lesson/207.html#mid=13704

 

1    重点关注

1.1    使用链表实现集合Set

详见3.1用链表实现的集合

 

 

2    课程内容


 

3    Coding

3.1    使用链表实现集合Set

  • 需求

使用链表实现的集合统计 傲慢与偏见 双城记两本书的英文词汇量

 

  • 链表
package com.company;

/***
 * 链表
 * @author weidoudou
 * @date 2022/10/28 7:56
 **/
public class LinkedList<E> {

    /**
     * 1  内部类node
     * @author weidoudou
     * @date 2022/10/28 7:59
     * @return null
     **/
    private class Node{
        //Node 只有两个属性,下一个节点和本节点存储的元素
        private E e;
        private Node next;

        /**
         * 通用调用node方法
         * @author weidoudou
         * @date 2022/10/28 8:17
         * @param e 请添加参数描述
         * @param  next 请添加参数描述
         * @return null
         **/
        public Node(E e,Node next){
            this.e = e;
            this.next = next;
        }

        /**
         * node 无参构造
         * @author weidoudou
         * @date 2022/10/28 8:15
         * @return null
         **/
        public Node(){
            this(null,null);
        }

        /**
         * node 有参构造
         * @author weidoudou
         * @date 2022/10/28 8:16
         * @param e 请添加参数描述
         * @return null
         **/
        public Node(E e){
            this(e,null);
        }


        @Override
        public String toString() {
            return e.toString();
        }
    }

    //2 LinkedList 属性 链表头元素(火车头),大小
    private int size;
    private Node dummyHead;

    /**
     * 3    LikedList 无参
     * @author weidoudou
     * @date 2022/10/28 8:27
     * @return null
     **/
    public LinkedList() {
        this.dummyHead = new Node(null,null);
        this.size = 0;
    }

    /**
     * 4  getSize
     * @author weidoudou
     * @date 2022/10/28 8:23
     * @return null
     **/
    public int getSize(){
        return size;
    }

    /**
     * 5  isEmpyt
     * @author weidoudou
     * @date 2022/10/28 8:24
     * @return boolean
     **/
    public boolean isEmpty(){
        return size == 0;
    }

    /**
     * 6  链表头部添加元素
     * @author weidoudou
     * @date 2022/10/28 8:37
     * @param e 请添加参数描述
     * @return void
     **/
    public void addFirst(E e){
        /*Node nodeNew = new Node(e);
        nodeNew.next = head;    //火车尾指向 上个尾巴
        this.head = nodeNew;    //火车尾 变成了当前的node*/

        //称之为优雅写法
        addElement(0,e);
    }

    /**
     * 7  链表尾部添加元素 认真分析下
     * @author weidoudou
     * @date 2022/10/28 18:11
     * @param e 请添加参数描述
     * @return void
     **/
    public void addLast(E e){
        addElement(size,e);
    }

    /**
     * 8  链表添加元素(链表通常不在中间添加元素,编写此段代码完全是为了后续便于理解和二叉树相关知识做铺垫)
     * @author weidoudou
     * @date 2022/10/28 8:45
     * @param index 请添加参数描述
     * @param  e 请添加参数描述
     * @return void
     **/
    public void addElement(int index,E e){
        if(index<0||index>size){
            throw new IllegalArgumentException("索引不正确");
        }


        Node pre = dummyHead;
        for(int i = 0;i<index;i++){
            pre = pre.next;
        }

        /*Node nodeNew = new Node(e);
        nodeNew.next = pre.next;
        pre.next = nodeNew;*/

        //优雅写法
        pre.next = new Node(e,pre.next);
        size++;
    }

    /**
     * 9    查询
     * @author weidoudou
     * @date 2022/10/29 11:18
     * @param index 请添加参数描述
     * @return E
     **/
    public E findByIndex(int index){
        if(index<0||index>size-1){
            throw new IllegalArgumentException("索引越界");
        }

        Node cur = dummyHead.next;
        for(int i = 0;i<index;i++){
            cur = cur.next;
        }
        return cur.e;
    }

    /**
     * A     查询首个元素
     * @author weidoudou
     * @date 2022/10/29 11:27
     * @return E
     **/
    public E findByFirst(){
        return findByIndex(0);
    }

    /**
     * B     查询最后一个元素
     * @author weidoudou
     * @date 2022/10/29 11:27
     * @return E
     **/
    public E findByLast(){
        return findByIndex(size-1);
    }

    /**
     * C     修改
     * @author weidoudou
     * @date 2022/10/29 11:29
     * @param index 请添加参数描述
     * @param  e 请添加参数描述
     * @return void
     **/
    public void update(int index,E e){
        if(index<0||index>size-1){
            throw new IllegalArgumentException("索引越界");
        }

        Node cur = dummyHead.next;
        for(int i = 0;i<index;i++){
            cur = cur.next;
        }
        cur.e = e;

    }

    /**
     * D     修改第一个元素
     * @author weidoudou
     * @date 2022/10/29 11:31
     * @param e 请添加参数描述
     * @return void
     **/
    public void updateFirst(E e){
        update(0,e);
    }

    /**
     * E    修改最后一个元素
     * @author weidoudou
     * @date 2022/10/29 11:31
     * @param e 请添加参数描述
     * @return void
     **/
    public void updateLast(E e){
        update(size-1,e);
    }

    /**
     * F     查询链表是否包含元素
     * @author weidoudou
     * @date 2022/10/29 13:04
     * @param e 请添加参数描述
     * @return boolean
     **/
    public boolean contains(E e){
        boolean flag;

        for(Node cur = dummyHead.next;cur!=null;cur=cur.next){
            if(e.equals(cur.e)){
                return true;
            }
        }
        return false;
    }

    /**
     * G      toString
     * @author weidoudou
     * @date 2022/10/29 13:06
     * @return java.lang.String
     **/
    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        for(Node cur = dummyHead.next;cur!=null;cur=cur.next){
            sb.append(cur+"->");
        }
        sb.append("Null");
        return sb.toString();
    }

    /**
     * H        删除索引为index的元素
     * @author weidoudou
     * @date 2022/10/29 19:40
     * @param index 请添加参数描述
     * @return E
     **/
    public E remove(int index){
        if(index<0||index>size-1){
            throw new IllegalArgumentException("索引越界");
        }

        Node pre = dummyHead;
        for(int i = 0;i<index;i++){
            pre = pre.next;
        }

        Node ret = pre.next;
        pre.next = ret.next;
        ret.next = null;
        size--;

        return ret.e;
    }

    /**
     * 删除第一个元素
     * @author weidoudou
     * @date 2022/10/30 14:56
     * @return E
     **/
    public E removFirst(){
        return remove(0);
    }

    /**
     * 删除最后一个元素
     * @author weidoudou
     * @date 2022/10/30 14:56
     * @return E
     **/
    public  E removLast(){
        return remove(size-1);
    }


    // 从链表中删除元素e
    public void removeElement(E e){

        Node prev = dummyHead;
        while(prev.next != null){
            if(prev.next.e.equals(e))
                break;
            prev = prev.next;
        }

        if(prev.next != null){
            Node delNode = prev.next;
            prev.next = delNode.next;
            delNode.next = null;
            size --;
        }
    }

}

 

  • Set接口
package com.company;

/**
 *  集合接口
 * @author weidoudou
 * @date 2022/12/14 8:14
 * @return null
 **/
public interface Set<E> {

    /**
     *  是否包含
     * @author weidoudou
     * @date 2022/12/14 8:17
     * @param e 请添加参数描述
     * @return boolean
     **/
    boolean contails(E e);

    /**
     *  是否为空
     * @author weidoudou
     * @date 2022/12/14 8:18
     * @return boolean
     **/
    boolean isEmpty();

    /**
     * 获取个数
     * @author weidoudou
     * @date 2022/12/14 8:19
     * @return int
     **/
    int getSize();

    /**
     * 添加方法
     * @author weidoudou
     * @date 2022/12/14 8:19
     * @param e 请添加参数描述
     * @return void
     **/
    void add(E e);

    /**
     * 删除方法
     * @author weidoudou
     * @date 2022/12/14 8:20
     * @param e 请添加参数描述
     * @return void
     **/
    void remove(E e);

}

 

  • LinkedList Set
package com.company;

public class LinkedListSet<E> implements Set<E>{

    private LinkedList<E> linkedList;

    public LinkedListSet(){
        linkedList = new LinkedList<>();
    }

    @Override
    public boolean contails(E e) {
        return linkedList.contains(e);
    }

    @Override
    public boolean isEmpty() {
        return linkedList.isEmpty();
    }

    @Override
    public int getSize() {
        return linkedList.getSize();
    }

    @Override
    public void add(E e) {
        if(!linkedList.contains(e)){
            linkedList.addFirst(e);
        }
    }

    @Override
    public void remove(E e) {
        if(linkedList.contains(e)){
            linkedList.removeElement(e);

        }
    }
}

 

  • 文件处理类:
package com.company;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Locale;
import java.io.File;
import java.io.BufferedInputStream;
import java.io.IOException;

// 文件相关操作
public class FileOperation {

    // 读取文件名称为filename中的内容,并将其中包含的所有词语放进words中
    public static boolean readFile(String filename, ArrayList<String> words){

        if (filename == null || words == null){
            System.out.println("filename is null or words is null");
            return false;
        }

        // 文件读取
        Scanner scanner;

        try {
            File file = new File(filename);
            if(file.exists()){
                FileInputStream fis = new FileInputStream(file);
                scanner = new Scanner(new BufferedInputStream(fis), "UTF-8");
                scanner.useLocale(Locale.ENGLISH);
            }
            else
                return false;
        }
        catch(IOException ioe){
            System.out.println("Cannot open " + filename);
            return false;
        }

        // 简单分词
        // 这个分词方式相对简陋, 没有考虑很多文本处理中的特殊问题
        // 在这里只做demo展示用
        if (scanner.hasNextLine()) {

            String contents = scanner.useDelimiter("\\A").next();

            int start = firstCharacterIndex(contents, 0);
            for (int i = start + 1; i <= contents.length(); )
                if (i == contents.length() || !Character.isLetter(contents.charAt(i))) {
                    String word = contents.substring(start, i).toLowerCase();
                    words.add(word);
                    start = firstCharacterIndex(contents, i);
                    i = start + 1;
                } else
                    i++;
        }

        return true;
    }

    // 寻找字符串s中,从start的位置开始的第一个字母字符的位置
    private static int firstCharacterIndex(String s, int start){

        for( int i = start ; i < s.length() ; i ++ )
            if( Character.isLetter(s.charAt(i)) )
                return i;
        return s.length();
    }
}

 

  • 测试类:
public static void main(String[] args) {

        System.out.println("pride and prejudice");
        ArrayList<String> words1  = new ArrayList<>();
        FileOperation.readFile("pride-and-prejudice.txt",words1);
        System.out.println("Total words:"+words1.size());

        Set<String> linkedListSet = new LinkedListSet<>();
        words1.stream().map(e->{
            linkedListSet.add(e);
            return e;
        }).collect(Collectors.toSet());
        System.out.println("Total different words:"+linkedListSet.getSize());



        System.out.println("a tale of two cities");
        ArrayList<String> words2  = new ArrayList<>();
        FileOperation.readFile("a-tale-of-two-cities.txt",words2);
        System.out.println("Total words:"+words2.size());

        Set<String> linkedListSet2 = new LinkedListSet<>();
        words2.stream().map(e->{
            linkedListSet2.add(e);
            return e;
        }).collect(Collectors.toSet());
        System.out.println("Total different words:"+linkedListSet2.getSize());
    }

 

  • 测试结果:
---- IntelliJ IDEA coverage runner ---- 
sampling ...
include patterns:
exclude patterns:
pride and prejudice
Total words:125901
Total different words:6530
a tale of two cities
Total words:141489
Total different words:9944
Class transformation time: 0.02436s for 386 classes or 6.310880829015544E-5s per class

Process finished with exit code 0

 

posted on 2022-12-18 22:26  菜鸟乙  阅读(111)  评论(0编辑  收藏  举报