线性表、队列和栈

集合操作------线性表

1、 List

2、 List的排序

3、 队列和栈

List

1、 get和set

List除了继承Collection定义的方法外,还根据其线性表的数据结构定义了一系列方法,其中最常用的就是基于下表的get和set方法:

--E get(int index):获取集合中指定下标对应的元素,下标从0开始。

--E set(intindex,E element):将给定元素存入给定位置,并将原位置的元素返回。

2、插入和删除

List根据下标的操作还支持插入与删除操作。

--add(int index,E element):将给定的元素插入到指定的位置,原位置及后续元素都顺序向后移动。

--remove(int index):删除给定位置的元素,并将被删除的元素返回。

3、ArrayList(变长数组)和LinkedList(双向循环列表)

List接口是Collection的子接口,用于定义线性表数据结构。可以将List理解为存放对象的数组,只不过其元素个数可以动态的增加或减少。

List接口的两个常见实现类为ArrayList和LinkedList,分别用动态数组和链表的方式实现了List接口。

可以认为ArrayList和LinkedList的方法再逻辑上完全一样,只是在性能上有一定的差别。ArrayList更适合随机访问,而LinkedList更适合在头部和尾部插入和删除。在性能要求不是特别苛刻的情况下可以忽略这个差别。

public void testList1() {
		Random rand=new Random();
		ArrayList<Integer> list1=new ArrayList<Integer>();
		LinkedList<Integer> list2=new LinkedList<Integer>();
		for(int i=0;i<10000;i++) {
			int j=rand.nextInt();
			list1.add(j);
			list2.add(j);
		}
		//反复在集合的头部(0号位置)添加删除元素
		long t1=System.nanoTime();//纳秒
		for(int i=0;i<10000;i++) {
			list1.add(0,5);//将5插入到0号位置,后面元素将顺序向后移动,是很消耗性能的。
			list1.remove(0);//将0号元素删掉,后面元素将顺序向前移动,是很消耗性能的。
		}
		long t2=System.nanoTime();
		for(int i=0;i<10000;i++) {
			list2.add(0,5);//插入,按位置插入
			list2.remove(0);//删除,按位置删除
		}
		long t3=System.nanoTime();
		System.out.println("顺序表消耗的时间:"+(t2-t1));//顺序表消耗的时间:26815138
		System.out.println("双向链表消耗的时间:"+(t3-t2));//双向链表消耗的时间:3252906
		//结论:LinkedList头尾添加和删除性能好于ArrayList
		
		t1=System.nanoTime();
		for(int i=0;i<10000;i++) {
			int n=list1.get(5000);//获取指定index位置的元素			
		}
		t2=System.nanoTime();
		for(int i=0;i<10000;i++) {
			int n=list2.get(5000);
		}
		t3=System.nanoTime();
		System.out.println("顺序表消耗的时间:"+(t2-t1));//顺序表消耗的时间:596195
		System.out.println("双向链表消耗的时间:"+(t3-t2));//双向链表消耗的时间:102743580
		//结论:ArrayList(中部)的读取性能好于LinkedList
		
		//当不知道该选用哪个List的时候,就选用ArrayList。
	}
public void testList() {
		List<String> list=new ArrayList<String>();
		list.add("Tom");//在尾部添加
		list.add("Jerry");//在尾部添加
		System.out.println(list);//[Tom, Jerry]
		                         //  0     1
		
		String name=list.get(1);//返回1号位置的元素
		System.out.println(name);//Jerry
		
		String one=list.set(1, "Nemo");//set 将1号位置的Jerry换成Nemo,并且将Jerry返回
		System.out.println(one);//Jerry
		System.out.println(list);//[Tom, Nemo]
		
		list.add(1, "Jerry");//在1的位置添加Jerry,其余的元素顺序后移
		System.out.println(list);//[Tom, Jerry, Nemo]
		
		list.remove(0);//将0号位置的元素删除,其余元素顺序向前移动
		System.out.println(list);//[Jerry, Nemo]
		
		//以上方法都是与index(位置)有关的操作方法,是List扩展的方法,此外List还从Collection继承了全部的集合操作方法
	}

4、 subList

List的subList方法用于获取子List。需要注意的是,subList获取的List与原List占有相同的存储空间,对subList的操作会影响原List。

List<E>subList(int fromIndex,int toIndex);fromIndex和toIndex是截取List的首尾下标,包括fromIndex,不包括toIndex。

public void testSublist() {
		List<String> cards=new ArrayList<String>();
		cards.add("黑桃2");//0
		cards.add("红桃2");//1
		cards.add("红桃10");//2
		cards.add("梅花10");//3
		cards.add("方片10");//4
		cards.add("黑桃10");//5
		cards.add("黑桃3");//6
		List<String> bomb=cards.subList(2, 6);//炸弹是从2到6,包括2,不包括6
		System.out.println(bomb);//[红桃10, 梅花10, 方片10, 黑桃10]
		bomb.clear();
		System.out.println(cards);//[黑桃2, 红桃2, 黑桃3]
		//list和sublist共享一块内存空间
	}

总结List

List继承了Collection,扩展了与位置有关的操作方法,实现类有两个:ArrayList和LinkedList,两个实现类的方法一致,都是List。任何时候,需要使用集合,但是不能确定使用哪个实现类的时候,首先选择ArrayList。

5、 List转换为数组

List的toArray方法用于将集合转换为数组。但实际上该方法是在Collection中定义的,所以所有的集合都具备这个功能。

其有两个方法:

   Object[] toArray;这个只能转换成Object类型的数组

public void testToArry1() {
		//Java先编译后运行,编译阶段没有对象,只有变量的类型,运行期间才有对象,对象可能是多态的。
		Collection<String> list=new ArrayList<String>();
		list.add("Tom");
		list.add("Andy");
		list.add("Nemo");
		list.add("Jerry");
		
		Object[] names=list.toArray();
		//names的每个元素变量类型是Object类型,元素变量类型不是String类型!不是String[]!
		//[Object[0],Object[1],...]
		System.out.println(Arrays.toString(names));//[Tom, Andy, Nemo, Jerry]
		//返回“运行期间”对象的类型!
		System.out.println(names[0].getClass().getName());//java.lang.String						
	}

   <T>T[] toArray(T[] a);可以转换成指定类型的数组,如果这个数组的长度小于数组元素的个数,则返回新数组。如果数组的长度大于数组元素的个数,返回原数组,没有值的数组位置存放null

public void testToArray2() {
		Collection<String> list=new ArrayList<String>();
		list.add("Tom");
		list.add("Andy");
		list.add("Nemo");
		list.add("Jerry");
		
		String[] name1=new String[2];//新建一个String类型的数组,长度为2,但是添加的元素个数是4,数组长度不够,则返回新数组
		String[] name2=new String[6];//新建一个String类型的数组,长度为6,但是添加的元素个数是4,没有值的填充0,返回原数组
		String[] name3=new String[list.size()];//最理想的情况下
		
		//返回的是String[]类型的数组
		name1=list.toArray(name1);//返回新数组
		name2=list.toArray(name2);//返回原数组
		name3=list.toArray(name3);//返回原数组
		
		System.out.println(Arrays.toString(name1));//[Tom, Andy, Nemo, Jerry]
		System.out.println(Arrays.toString(name2));//[Tom, Andy, Nemo, Jerry, null, null]
		System.out.println(Arrays.toString(name3));//[Tom, Andy, Nemo, Jerry]
	}

6、 数组转换为List

Arrays类中提供了一个静态方法asList,使用该方法我们可以将一个数组转换为对应的List集合。返回的List的集合元素类型由传入的数组的元素类型决定。并且需要注意的是,返回的集合我们不能对其进行增删元素,否则会抛出异常。并且对集合的元素进行修改会影响数组对应的元素。

public void testAsList() {
		//数组转换为List
		String[] names= {"Tom","Andy","Jerry"};
		//list是静态的list,长度不能改变,也就是不能调用add和remove
		List<String> list1=Arrays.asList(names);
		//静态list和name共享同一个内存空间,改数组,list也会被更改
		//不是ArrayList也不是LinkedList,这个list的类型是内部类
		System.out.println(list1.getClass().getName());//java.util.Arrays$ArrayList是一个内部类
		System.out.println(list1);//[Tom, Andy, Jerry]
		//list1.remove(0);//会出现运行异常,不支持的操作
		//list1.add();
		
		//数组转换为List的第二种方法
		List<String> list2=new ArrayList<String>();
		//list2和name不共享内存空间,更改数组,对list没有影响
		Collections.addAll(list2, names);//将names中所有元素添加到list2中
		System.out.println(list2.getClass().getName());//java.util.ArrayList
		System.out.println(list2);
		
		//静态List与数组names共享相同的存储空间
		//修改数组names影响线性表List
		names[1]="Lee";
		System.out.println(list1);//[Tom, Lee, Jerry]
		System.out.println(list2);//[Tom, Andy, Jerry]
	}

List的排序:

排序:按照一定的大小顺序排序

比较大小:比较两个元素的大小

public void testStringCompare() {
		//String类型如何比较大小
		//在String类中有一个方法compareTo
		String s1;
		String s2;
		s1="A";
		s2="B";
		if(s1.compareTo(s2)>0) {
			System.out.println("s1大于s2");
		}
		if(s1.compareTo(s2)<0) {
			System.out.println("s1小于s2");
		}
		if(s1.compareTo(s2)==0) {
			System.out.println("s1等于s2");
		}
		//String是可以比较大小的,包含默认
		//比较大小的方法compareTo
		//Java中凡是可以默认比较大小的类型,都有compareTo,比如:包装类Date
		//有compareTo方法的类,称为可以自然的类
		//compareTo是compareable接口定义的方法,可以自然排序的类都实现了这个接口
		//凡是实现compareable,实现了compareTo方法的类,都可以进行自然(默认)排序。
	}

1、 Collections.sort方法实现排序

Collections是集合的工具类,它提供了很多便于我们操作集合的方法,其中就有用于集合排序的sort方法。

该方法的定义为:

--voidsort(List<T> list):该方法的作用是对给定的集合元素进行自然排序。

List的每个元素要有默认比较规则,sort根据元素的默认比较规则进行排序,若没有默认的比较规则,则不能排序。

    public void testSort1() {
		List<Integer> list=new ArrayList<Integer>();
		Random ran=new Random();
		for(int i=0;i<10;i++) {
			list.add(ran.nextInt(100));
		}
		System.out.println(list);//[16, 44, 85, 60, 19, 98, 31, 57, 78, 97]
		
		Collections.sort(list);
		System.out.println(list);//[16, 19, 31, 44, 57, 60, 78, 85, 97, 98]
	}
	
	public void testSort2() {
		//默认的自然排序:调用比较规则compareTo
		List<String> names=new ArrayList<String>();
		Collections.addAll(names, "Tom","Jerry","Andy","John");
		System.out.println(names);//[Tom, Jerry, Andy, John]
		Collections.sort(names);
		System.out.println(names);//[Andy, Jerry, John, Tom]
	}

2、 Comparator:自定义排序

一旦Java类实现了Comparable接口,其比较逻辑就已经确定;如果希望在排序的操作中临时指定比较规则,可以采用Comparable接口回调的方式。Comparable接口要求实现类必须重写其定义的方法:

--int compare(To1,T o2)

该方法的返回值要求:

--若o1>o2,则返回值应>0

--若o1<o2,则返回值应<0

--若o1==o2,则返回值应为0

利用方法:

      Collections.sort(list,构造器)

就可以进行任意规则的排序

        public void testSort3() {
		//自定义的比较器:按照字符长度比较大小
		Comparator<String> byLength=new Comparator<String>() {
			public int compare(String o1,String o2) {
				return o1.length()-o2.length();
			}
		};//内部类
		String s1="abcde";
		String s2="好好学习we";
		System.out.println(byLength.compare(s1,s2));
		
		
		List<String> names=new ArrayList<String>();
		Collections.addAll(names, "Tom","Jerry","Andy","John");
		System.out.println(names);//[Tom, Jerry, Andy, John]
		//对names按照字符串长度比较大小进行排序,这是Andy和John谁在前面都可以,因为长度一样
		Collections.sort(names, byLength);
		System.out.println(names);//[Tom, Andy, John, Jerry]
		//sort方法封装了排序算法,按照从小到大排序,是依照byLength中的compare()方法的结果比较大小排序
	}

	public void testSort4() {
		//实现按字符串倒序排序的算法
		String s1="abc";
		String s2="zde";
		//s1.compareTo(s2)<0
		Comparator<String> byValue=new Comparator<String>() {
			public int compare(String o1,String o2) {
				return -(o1.compareTo(o2));//按照z到a的顺序排序
			}
		};
		System.out.println(s1.compareTo(s2));//-25
		System.out.println(byValue.compare(s1, s2));//25
		
		List<String> list=new ArrayList<String>();
		Collections.addAll(list, "abc","d","f","z");
		System.out.println(list);//[abc, d, f, z]
		Collections.sort(list, byValue);
		System.out.println(list);//[z, f, d, abc]
	}
	
	public void testSort5() {
		Comparator<Person> byAgeHeight=new Comparator<Person>() {
			public int compare(Person o1, Person o2) {
				先按照年龄比较,年龄如果相同就按照身高比较
				if(o1.age==o2.age) {
					return o1.height-o2.height;
				}
				return o1.age-o2.age;
			}
		};
		//先按照年龄比较,年龄如果相同就按照身高比较
		List<Person> list=new ArrayList<Person>();
		list.add(new Person("Tom",4,35));
		list.add(new Person("Jerry",10,22));
		list.add(new Person("Andy",20,11));
		list.add(new Person("Nemo",2,35));
		list.add(new Person("Lee",4,20));
		System.out.println(list);//[Tom:4:35, Jerry:10:22, Andy:20:11, Nemo:2:35, Lee:4:20]
		Collections.sort(list, byAgeHeight);
		System.out.println(list);//[Nemo:2:35, Lee:4:20, Tom:4:35, Jerry:10:22, Andy:20:11]
	}
	class Person{
		String name;
		int age;
		int height;
		public Person(String name,int age,int height) {
			this.name=name;
			this.age=age;
			this.height=height;
		}
		public String toString() {
			return name+":"+age+":"+height;
		}
	}

关于自定义排序:

1、Comparable可比较的,这个接口不常用,是默认比较规则接口,实现这个接口的类可以进行“自然排序”。Java API中有些类型实现了这个接口:String、包装类、时间等。实现这个接口必须保证:equals  compareTo  hashCode的一致性,当两个对象equals结果为true的时候,compareTo结果为0,同时具有相同的hashCode。

2、Comparator:比较器,用于实现某两个对象的自定义比较大小,没有限定,可以按照任何属性和算法比较,是常用的比较规律,可以利用这个比较器,进行任意的排序。

3、Java自带的排序算法都是升序排序,可以利用比较规则影响排序结果。

Collections

Collections是集合的工具类,包含大量的集合工具方法(算法):填充Collections.addAll(),排序Collections.sort()、查找、二分查找等。去java2s.com这个网站中查看具体的。

队列和栈:

1、Queue

队列遵循先进先出原则,一端进,一端出。

JDK提供了Queue接口,同时使得LinkedList实现了该接口。选择LinkedList实现Queue的原因在于Queue经常要进行添加和删除的操作,而LinkedList在这方面效率高。

Queue接口主要方法如下:

1、boolean offer(E e):将一个对象添加至队尾,如果添加成功则返回true

2、E poll():从队首删除并返回一个元素。

3、E peek():返回队首的元素(但不删除)。

4、queue.isEmpty();

5、queue.size();

public void testQueue() {
		Queue<String> queue=new LinkedList<String>();
		queue.offer("a");
		queue.offer("b");
		queue.offer("c");
		System.out.println(queue);//[a,b,c]
		String str=queue.peek();//返回队首的元素
		System.out.println(str);//a
		while(queue.size()>0) {
			str=queue.poll();//从队首删除并返回一个元素。
			System.out.print(str+" ");//a b c
		}				
	}

1、 Deque

Deque是Queue的子接口,定义了所谓的双端队列,即从队列的两端分别可以入队(offer)和出队(poll),LinkedList实现了该接口。

2、

如果将Deque限制为只能从一端入队和出队,则可实现栈(Stack)的数据结构,对于栈而言,入栈称之为push,出栈称之为pop。栈遵循先进后出的原则。

    public void testStack() {
		Deque<String> stack=new LinkedList<String>();
		stack.push("a");
		stack.push("b");
		stack.push("c");
		System.out.println(stack);//[c,b,a]
		String str=stack.peek();//c
		System.out.println(str);
		while(stack.size()>0) {
			str=stack.pop();
			System.out.print(str+" ");//c b a
		}
	}

栈的方法:

1、stack.push();

2、stack.pop();

3、stack.peek();

4、stack.isEmpty();

5、stack.empty();

6、stack.size();


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值