Java SE入门及基础(50)& Java实现LinkedList(单向链表、双向链表)& Java实现栈

目录

[List 接口](#List 接口)

[1. 特性描述](#1. 特性描述)

[List 接口常用方法](#List 接口常用方法)

[2. ArrayList](#2. ArrayList)

示例及源码解读

[3. LinkedList](#3. LinkedList)

示例及源码解读

单向链表

双向链表

[4. 栈](#4. 栈)

练习

[Java SE文章参考:Java SE入门及基础知识合集-CSDN博客](#Java SE文章参考:Java SE入门及基础知识合集-CSDN博客)

List 接口

**1.**特性描述

A List is an ordered Collection (sometimes called a sequence). Lists may contain duplicate elements.
列表是有序的集合(有时称为序列)。 列表可能包含重复的元素。
The Java platform contains two general-purpose List implementations. ArrayList, which is usually the better-performing implementation, and LinkedList which offers better performance under certain circumstances.
Java 平台包含两个常用的 List 实现。 ArrayList 通常是性能较好的实现,而 LinkedList 在某些情况下可以提供更好的性能。

List 接口常用方法

E get ( int index ); // 获取给定位置的元素
E set ( int index , E element ); // 修改给定位置的元素
void add ( int index , E element ); // 在给定位置插入一个元素
E remove ( int index ); // 移除给定位置的元素
int indexOf ( Object o ); // 获取给定元素第一次出现的下标
int lastIndexOf ( Object o ); // 获取给定元素最后一次出现的下标
ListIterator < E > listIterator (); // 获取 List 集合专有的迭代器
ListIterator < E > listIterator ( int index ); // 获取 List 集合专有的迭代器,从给定的下标位置开始的迭代器
List < E > subList ( int fromIndex , int toIndex ); // 获取 List 集合的一个子集合

**2.**ArrayList

示例及源码解读

import java . util . ArrayList ;
import java . util . Iterator ;
import java . util . List ;
import java . util . ListIterator ;
public class ArrayListTest {
public static void main ( String \[\] args ) {
//集合有序是指存储顺序与遍历时取出来的顺序一致
ArrayList < String > list = new ArrayList <> ();
list . add ( "a" ); // 第一次调用 size =0;
list . add ( "a" );
list . add ( "b" );
list . add ( "c" );
list . add ( "d" );
list . add ( 2 , "n" ); // a a b c d => a a b b c d => a a n b c d
String old = list . set ( 1 , "g" );
System . out . println ( old );
System . out . println ( "====================" );
for ( String str : list ){
System . out . println ( str );
}
System . out . println ( "====================" );
Iterator < String > iter = list . iterator ();
while ( iter . hasNext ()){
String s = iter . next ();
System . out . println ( s );
}
System . out . println ( "====================" );
ListIterator < String > listIterator = list . listIterator ();
while ( listIterator . hasNext ()){
String s = listIterator . next ();
System . out . println ( s );
}
System . out . println ( "====================" );
ListIterator < String > prevIterator = list . listIterator ( list . size ());
while ( prevIterator . hasPrevious ()){
String s = prevIterator . previous ();
System . out . println ( s );
}
System . out . println ( "====================" );
List < String > subList = list . subList ( 2 , 4 );
for ( String str : subList ){
System . out . println ( str );
}
System . out . println ( "====================" );
int size = list . size ();
for ( int i = 0 ; i < size ; i ++ ){
String s = list . get ( i );
System . out . println ( s );
}
System . out . println ( "===================" );
ArrayList < Integer > numbers = new ArrayList <> ();
numbers . add ( 1 );
numbers . add ( 2 );
numbers . add ( 3 );
numbers . add ( 4 );
//移除下标为 3 这个位置的元素
numbers . remove ( 3 ); // 这是移除下标为 3 这个位置的元素还是移除 3 这个元素?
//移除 3 这个元素
numbers . remove (( Integer ) 3 );
for ( Integer number : numbers ){
System . out . println ( number );
}
numbers . add ( 2 );
numbers . add ( 2 );
int index1 = numbers . indexOf ( 2 );
int index2 = numbers . lastIndexOf ( 2 );
System . out . println ( index1 );
System . out . println ( index2 );
}
}

  • ArrayList 继承于 AbstractList , AbstractList 继承于 AbstractColletion
  • ensureCapacityInternal(int minCapacity) 确保数组有足够的容量来存储新添加的数据
  • void grow(int minCapacity) 实现数组扩容,扩容至原来的1.5倍
  • ListItr 可以从前到后对集合进行遍历,也可以从后往前对集合进行遍历,还可以向集合中添加元素,修改元素。而 Itr 只能从前到后对集合进行遍历。
    ArrayList底层采用的是数组来存储元素,根据数组的特性, ArrayList 在随机访问时效率极高,在增加 和删除元素时效率偏低,因为在增加和删除元素时会涉及到数组中元素位置的移动。 ArrayList 在扩容 时每次扩容到原来的 1.5

**3.**LinkedList

示例及源码解读

单向链表

package com . wq . list ;
/**
* 自定义单向链表
* @param <T> 泛型变量
*/
public class MyNode < T > {
private T data ; // 链中存储的数据
private MyNode < T > next ; // 下一个链
public MyNode ( T data , MyNode < T > next ) {
this . data = data ;
this . next = next ;
}
public T getData () {
return data ;
}
public void setData ( T data ) {
this . data = data ;
}
public MyNode < T > getNext () {
return next ;
}
public void setNext ( MyNode < T > next ) {
this . next = next ;
}
}
package com . wq . list ;
public class MyNodeTest {
public static void main ( String \[\] args ) {
MyNode < String > first = new MyNode <> ( " 第一个链 " , null );
MyNode < String > second = new MyNode <> ( " 第二个链 " , null );
first . setNext ( second );
MyNode < String > third = new MyNode <> ( " 第三个链 " , null );
second . setNext ( third );
MyNode < String > fourth = new MyNode <> ( " 第四个链 " , null );
third . setNext ( fourth );
MyNode < String > nextNode = first ;
while ( nextNode != null ){
System . out . println ( nextNode . getData ());
nextNode = nextNode . getNext ();
}
System . out . println ( "===================" );
MyNode < Integer > number4 = new MyNode <> ( 4 , null );
MyNode < Integer > number3 = new MyNode <> ( 3 , number4 );
MyNode < Integer > number2 = new MyNode <> ( 2 , number3 );
MyNode < Integer > number1 = new MyNode <> ( 1 , number2 );
MyNode < Integer > next = number1 ;
while ( next != null ){
System . out . println ( next . getData ());
next = next . getNext ();
}
}
}

双向链表

package com . wq . list ;
/**
* 自定义双向链表
* @param <T>
*/
public class DeNode < T > {
private T data ; // 链中存储的数据
private DeNode < T > prev ; // 前一个链
private DeNode < T > next ; // 后一个链
public DeNode ( T data , DeNode < T > prev , DeNode < T > next ) {
this . data = data ;
this . prev = prev ;
this . next = next ;
}
public T getData () {
return data ;
}
public void setData ( T data ) {
this . data = data ;
}
public DeNode < T > getPrev () {
return prev ;
}
public void setPrev ( DeNode < T > prev ) {
this . prev = prev ;
}
public DeNode < T > getNext () {
return next ;
}
public void setNext ( DeNode < T > next ) {
this . next = next ;
}
}
package com . wq . list ;
public class DeNodeTest {
public static void main ( String \[\] args ) {
DeNode < Integer > number1 = new DeNode <> ( 1 , null , null );
DeNode < Integer > number2 = new DeNode <> ( 2 , number1 , null );
number1 . setNext ( number2 );
DeNode < Integer > number3 = new DeNode <> ( 3 , number2 , null );
number2 . setNext ( number3 );
DeNode < Integer > number4 = new DeNode <> ( 4 , number3 , null );
number3 . setNext ( number4 );
DeNode < Integer > nextNode = number1 ;
while ( nextNode != null ){
System . out . println ( nextNode . getData ());
nextNode = nextNode . getNext ();
}
System . out . println ( "==================" );
DeNode < Integer > prevNode = number4 ;
while ( prevNode != null ){
System . out . println ( prevNode . getData ());
prevNode = prevNode . getPrev ();
}
}
}

  • LinkedList 继承于 AbstractSequentialList , AbstractSequentialList 继承于 AbstractList , AbstractList 继承于 AbstractColletion
  • void addFirst(E e) 将数据存储在链表的头部
  • void addLast(E e) 将数据存储在链表的尾部
  • E removeFirst() 移除链表头部数据
  • E removeLast() 移除链表尾部数据

package com . wq . list ;
import java . util . LinkedList ;
public class LinkedListTest {
public static void main ( String \[\] args ) {
LinkedList < String > list = new LinkedList <> ();
list . add ( " 第一个字符串 " );
list . add ( " 第二个字符串 " );
list . addLast ( " 第三个字符串 " );
list . addFirst ( " 第四个字符串 " );
String first = list . removeFirst (); // 将第一个链移除
String last = list . removeLast (); // 将最后一个链移除
System . out . println ( first );
System . out . println ( last );
first = list . getFirst ();
last = list . getLast ();
System . out . println ( first );
System . out . println ( last );
}
}
LinkedList底层采用的是双向链表来存储数据,根据链表的特性可知, LinkedList 在增加和删除元素时 效率极高,只需要链之间进行衔接即可。在随机访问时效率较低,因为需要从链的一端遍历至链的另一 端。

**4.**

package com . wq . list ;
import java . util . ArrayList ;
/**
* 自定义栈:后进先出
*/
public class MyStack < T > extends ArrayList < T > {
public void push ( T t ){
add ( t );
}
public T pop (){
if ( size () == 0 ) throw new IllegalArgumentException ( " 栈里没有数据啦 " );
T t = get ( size () - 1 );
remove ( t );
return t ;
}
}
package com .wq . list ;
public class MyStackTest {
public static void main ( String \[\] args ) {
MyStack < Integer > stack = new MyStack <> ();
stack . push ( 1 );
stack . push ( 2 );
stack . push ( 3 );
stack . push ( 4 );
stack . push ( 5 );
while ( ! stack . isEmpty ()){
System . out . println ( stack . pop ());
}
}
}

练习

从控制台录入5 位学生信息:姓名,性别,年龄,成绩,并将这些学生信息以 "," 衔接起来,然后存储至文本中。然后再从文本中将这些信息读取至集合中。

package com . wq . list ;
import java . io . * ;
import java . util . ArrayList ;
import java . util . List ;
import java . util . Scanner ;
/**
* 从控制台录入 5 位学生信息:姓名,性别,年龄,成绩,并将这些学生信息以 "," 衔接起来,
* 然后存储至文本中。然后再从文本中将这些信息读取至集合中。
*/
public class Exercise {
public static void main ( String \[\] args ) {
List < Student > students = new ArrayList <> ();
Scanner sc = new Scanner ( System . in );
for ( int i = 0 ; i < 5 ; i ++ ){
System . out . println ( " 请输入姓名: " );
String name = sc . next ();
System . out . println ( " 请输入性别: " );
String sex = sc . next ();
System . out . println ( " 请输入年龄: " );
int age = sc . nextInt ();
System . out . println ( " 请输入成绩: " );
double score = sc . nextDouble ();
students . add ( new Student ( name , sex , age , score ));
}
saveStudents ( students , "F:\\stu\\stu.txt" );
List < Student > read = readStudents ( "F:\\stu\\stu.txt" );
for ( Student stu : read ){
System . out . println ( stu );
}
}
public static List < Student > readStudents ( String path ){
List < Student > students = new ArrayList <> ();
try ( FileReader reader = new FileReader ( path );
BufferedReader br = new BufferedReader ( reader );){
String line ;
while (( line = br . readLine ()) != null ){
String \[\] arr = line . split ( "," );
//name + "," + sex +"," + age + "," + score;
String name = arr 0 ;
String sex = arr 1 ;
int age = Integer . parseInt ( arr 2 ); // Float.parseFloat()
double score = Double . parseDouble ( arr 3 );
students . add ( new Student ( name , sex , age , score ));
}
} catch ( FileNotFoundException e ) {
e . printStackTrace ();
} catch ( IOException e ) {
e . printStackTrace ();
}
return students ;
}
public static void saveStudents ( List < Student > students , String path ){
File file = new File ( path );
File parent = file . getParentFile ();
if ( ! parent . exists ()) parent . mkdirs ();
try ( FileWriter writer = new FileWriter ( file );
BufferedWriter bw = new BufferedWriter ( writer );){
for ( Student stu : students ){
bw . write ( stu . toString ());
bw . newLine ();
}
bw . flush ();
} catch ( IOException e ) {
e . printStackTrace ();
}
}
}

Java SE文章参考:Java SE入门及基础知识合集-CSDN博客

相关推荐
Scott9999HH2 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔2 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社3 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海3 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖4 小时前
JDK 26 新特性详解
java·开发语言
马优晨4 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区6 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大7 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai7 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说7 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json