Collection集合(上) -- list

 

集合(Collection<E>):是一个容器,可以存储多个数据且长度不确定

<E> ------- 泛型 : 用于指定集合元素的数据(对象)类型,由泛型指定的元素类型都要是引用类型

int[ ] a; a ----------数组类型,a中的元素类型式整型

Collection<String> c ; c 是集合类型(引用类型),元素类型是String

Collection<Integer> c;存储 1.2.3 整型值(基本类型数据也可以进行存储-–-–--—转成对应的包装类)

 

Collection<E> 是集合的顶级接口

子接口:List,Set,Queue,Deque 。。。。

list(序列,列表): 有序

存入数据有序,可以通过下标进行操作

import java.util.ArrayList;
import java.util.List;
​
public class ListDemo{
    public static void main(String[] args) {
        //c创建了一个集合对象
        List<String> list = new ArrayList<>();
        //添加对象
        list.add("a");
        list.add("f");
        list.add("c");
        list.add("b");
        //插入元素
        list.add(0, "1");
        //末尾添加
        list.add(5, "2");
        
        System.out.println(list);   //[1, a, f, c, b, 2]
        
        //根据下标进行删除
        list.remove(0);
        //删除具体元素
        //如果要删除的元素不在集合中,就不执行
        list.remove("9");
        
        System.out.println(list);   //[a, f, c, b, 2]
        
        //判断字符串是否在几何中
        System.out.println(list.contains("2")); //true
        
        //获取元素,根据下标值,返回集合对应的元素值
        System.out.println(list.get(1));    //f
        
        //根据元素值,返回对应集合的下标值,如果没有返回-1
        System.out.println(list.indexOf("c"));  //2
        
        //判断集合中是否含有元素
        System.out.println(list.isEmpty());     //false
        
        //替换
        System.out.println();
        //清空集合
        list.clear();
        System.out.println(list);   //[]
        
        
    }   
}
import java.util.ArrayList;
import java.util.List;
​
public class ListDemo{
    public static void main(String[] args) {
        //c创建了一个集合对象
        List<String> list = new ArrayList<>();
        //添加对象
        list.add("a");
        list.add("f");
        list.add("c");
        list.add("b");
​
//      list.remove(1);
//      list.add(1, "2");
//      System.out.println(list);
        //根据下标修改元素
        list.set(1, "2");
        System.out.println(list);
        
        //返回集合中元素的个数
        System.out.println(list.size());    //4
        
        
        //返回一个子列表,左闭右开
        System.out.println(list.subList(1, 3)); //[2, c]
        
    }   
}
​
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
​
public class ListDemo{
    public static void main(String[] args) {
        //c创建了一个集合对象
        List<String> list = new ArrayList<>();
        //添加对象
        list.add("a");
        list.add("f");
        list.add("c");
        list.add("b");
​
        //再转数组过程中,指定要转成的类型
        String[] ss=list.toArray(new String[0]);
        System.out.println(Arrays.toString(ss));    //[a, f, c, b]
        
        
    }   
}
 

list实现类:ArrayList,LinkList, Vector,Stack

 

ArrayList(顺序表):

基于数组实现,默认数组的初始容量为10,默认扩容是基于右移运算,在原来的基础上加上一半 10 10+5 15+7 ......

查询效率较高,增删元素效率较低,是一个线程不安全的集合

练习:通过数组实现ArrayList

import java.util.Arrays;
​
/*
 * 通过数组实现ArrayList
 * 
 * */
public class ListDemo {
    public static void main(String[] args) {
        
            ListArray list = new ListArray();
            list.add("a");
            list.add("b");
            list.add("c");
            list.add("d");
            list.add(0,"1");
            list.add(5,"2");
            list.remove(0);
            list.remove("2");
            
            System.out.println(list);
    }
}
​
class ListArray {
    // 存储数据的数组
    String[] date;
    // 表示元素个数
    int size = 0;
​
    // 无参构造
    public ListArray() {
        // 默认长度为10
        date = new String[10];
    }
​
    // 有参构造------指定数组长度
    public ListArray(int initCapcity) {
        date = new String[initCapcity];
    }
​
    //数组扩容
    public void grow(){
        //处理特殊的情况,数组长度为0和1的情况
        if(date.length<=1){
            date = Arrays.copyOf(date, date.length+1);
        }else {
            //在原来的基础上加一半
            date = Arrays.copyOf(date, date.length+(date.length>>1));
        }
        
    }
    
    //下标越界
    public void out(int index){
        //判断下标是否越界
        if(size >=date.length){
            grow();
        }
    }
    
    
    // 添加元素
    public void add(String str) {
        
        //判断是否需要扩容
        if(size>=date.length){
            grow();
        }
        
        //添加元素,数组下标往后挪动,集合元素+1
        date[size++]=str;
        
    }
    
    //插入
    public void add(int index,String str){
        //判断下标是否越界
        if(index<0||index>size){
            throw new IllegalArgumentException("index:"+index);
        }
        
        //判断是否需要扩容
        if(size>=date.length){
            grow();
        }
        
        //开始插入
        //法一
        //依次遍历后面需要移动的元素
//      for(int i=size-1;i>=index;i--){
//          //依次进行前面的值赋值给后面的值
//          date[i+1] = date[i];
//      }
//      
        //法二
        System.arraycopy(date, index, date, index+1,size-index );
        //插入值
        date[index]=str;
        //元素加1
        size++;
    }
    
    
    //删除
    public void remove(int index ){
        //下标越界
        out(index);
        
//可以进行删除
//依次遍历需要移动的元素
for(int i=index;i<size-1;i++){
//后面的值赋值给前面的值
date[i]= date[i+1];
    }

//    System.arraycopy(date,index+1,date,index,size-(index+1));

//元素减1
size--;
    }

//删除----根据元素
public void remove(String str){
//返回参数对应的下标值
int index = indexOf(str);
//判断下标值是否等于-1
if(index!=-1){
remove(index);
    }
    }

//返回第一次出现的下标值
public int indexOf(String str){
for(int i =0;i < size;i++){
//判断参数与数值是否相等
if(str==date[i]||str!=null&&str.equals(date[i])){
return i;
    }
    }

return -1;
    }

//清空列表
public void clear(){
//让元素个数为0
size=0;
    }

//是否包含
public boolean contains(String str){
//表示在列表中是否出现
return indexOf(str)!=-1;
    }

//获取元素
public String get(int index){
//判断参数是否越界
out(index);
//返回下标值
return date[index];
    }

//判断列表是否为空
public boolean isEmpty(){
return size==0;
    }

//替换元素
public void set(int index,String str){
//判读那参数是否越界
out(index);
//替换
date[index]=str;
    }

//返回元素个数
public int size(){
return size;
    }

//截取子列表
public ListArray subList(int fromindex,int toindex){
//判断参数是否都越界
out(fromindex);
out(toindex);

//判断起始下标是否小于结束下标
if(fromindex>toindex){
throw new IllegalArgumentException("FromIndex:"+fromindex);
    }
//截取的元素个数
int count = toindex - fromindex;

//创建新列表
ListArray list = new ListArray();
//数组之间的复制(原数组和新数组的复制)
System.arraycopy(date, fromindex, list.date, 0, count);
//改变新列表的元素个数
list.size=count;

//返回子列表
return list;
    }

//重写toString方法
@Override
public String toString(){
//创建对象进行拼接
StringBuilder sb = new StringBuilder("[");
//遍历数组元素进行拼接
for(int i= 0; i<size;i++){
sb.append(date[i]).append(", ");
    }

//转成字符串
String str = sb.toString();

//截取子串
if(size>0){
str = str.substring(0,str.length()-2);
    }
return str+="]";
    }
}

 

 

LinkedList(链表)

底层基于节点进行实现的,底层内存不连续,增删元素效率较高,查询元素效率较低,是一个线程不安全的集合。

练习,实现LinkedList

  思考:在某个场景下,列表的增删与查询出现的机率几乎一致,用ArrayList还是LinkedList?

  LinkedList:时间消耗差不多,ArrayList会进行扩容操作,会降低内存利用率,而LinkedList不会出现大量的空间占用

import java.util.LinkedList;
​
/*
 * 实现LinkedList
 */
public class ListDemo {
    public static void main(String[] args) {
    LinkedList<String> str = new LinkedList<String>();
    str.addAll(str);
    }
}
​
class ListLinked{
    //节点个数
    int size=0;
    //头节点
    Node first;
    //尾节点
    Node last;
    
    
    //内部类---节点
    class Node{
        //存储的元素
        String item; 
        //上一个节点
        Node prev;
        //下一个节点
        Node next;
        
        //有参构造
        public Node(String item,Node prev,Node next){
            this.item=item;
            this.next=next;
            this.prev = prev;
            
        }
        
    }
    
    public void add(String str){
        //创建一个新节点
        Node node = new Node(str, null, null);
        
        //判断在什么位置进行添加节点
        if(size==0){    //表明链表无节点,添加第一个节点
            //头节点要指向新节点
            this.first = node;
        }else{          //添加最后一个节点
            //原最后一个节点的下一个节点指向新节点
            this.last.next = node;
            //新节点的上一个节点指向左后一个节点
            node.prev=this.last;
        }
        //尾节点指向新节点
        this.last=node;
    }
    
    
    //插入
    public void add(int index,String str){
        //判断下标是否越界
        if(index<0||index>size){
            throw new IllegalArgumentException("Index:"+index);
        }
        
        //创建新节点
        Node node = new Node(str,null,null);
        
        //判断插入的位置
        if(index==0){       //插到第一个节点
            
            //判断插入第一个节点之前,链表是否还有其他节点
            if(size==0){
                add(str);
                //保证添加一个节点,size就加一次
                return;
            }
            
            //有其他节点的插入情况
            //原第一个节点的上一个节点指向新节点
            this.first.prev = node;
            //新节点的下一个节点指向原第一个节点
            node.next= this.first;
            //头节点指向新节点
            this.first=node;
        }else if(index==size){  //添加最后一个节点
            //
            add(str);
            //保证添加一个节点
            return;
        }else{                  //在中间位置进行添加
            //通过下标找到对应的节点
            Node no = this.first;
            for(int i = 0;i<index;i++){
no=no.next;
    }
//no节点的上一个节点的下一个节点,指向新节点
no.prev.next = node;
//新节点的上一个节点指向no的下一个节点
no.prev=no.prev;
//no节点的上一个节点指向新节点
no.prev=node;
//新节点的下一个节点指向no节点
//    no.next=node;
    }

​
    }
}

 

 

posted @ 2020-08-19 09:11  minnersun  阅读(81)  评论(0)    收藏  举报