首先定义接口 List<E>
,以下是对每个方法的详细解释:
int size()
: 返回列表中元素的数量。boolean isEmpty()
: 判断列表是否为空,如果为空则返回true,否则返回false。boolean contains(Object o)
: 判断列表是否包含指定的元素,如果包含则返回true,否则返回false。Object[] toArray()
: 将列表转换为一个数组。boolean add(E e)
: 将指定的元素添加到列表的末尾,并返回true。boolean remove(Object o)
: 从列表中移除指定的元素,如果成功移除则返回true,否则返回false。boolean containsAll(List<E> c)
: 判断列表是否包含另一个集合中的所有元素,如果是则返回true,否则返回false。boolean addAll(List<? extends E> c)
: 将另一个集合中的所有元素添加到列表的末尾,如果成功添加则返回true。boolean addAll(int index, List<? extends E> c)
: 在指定位置插入另一个集合中的所有元素。boolean removeAll(List<?> c)
: 移除列表中与另一个集合相同的所有元素。void clear()
: 移除列表中的所有元素,使其为空。E get(int index)
: 返回指定位置的元素。E set(int index, E element)
: 将指定位置的元素替换为新的元素,并返回原来的元素。void add(int index, E element)
: 在指定位置插入一个元素。E remove(int index)
: 移除并返回指定位置的元素。int indexOf(Object o)
: 返回指定元素在列表中第一次出现的位置索引,如果不存在则返回-1。
这个接口定义了列表常用的操作,实现这个接口的类需要提供对应的方法实现,例如ArrayList或LinkedList。
public interface List<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Object[] toArray();
boolean add(E e);
boolean remove(Object o);
boolean containsAll(List<E> c);
boolean addAll(List<? extends E> c);
boolean addAll(int index, List<? extends E> c);
boolean removeAll(List<?> c);
void clear();
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
}
接下来是一个使用链表实现的自定义泛型列表类 TLinkedList
,实现了之前提到的 List
接口。以下是对代码的详细解释:
-
Node 类:
Node<E>
是一个节点类,包含一个数据域value
和一个指向下一个节点的引用next
。- 构造方法
Node(E o, Node<E> next)
用于初始化节点。
class Node<E> {
E value;
Node<E> next;
public Node(E o, Node<E> next){
this.value = o;
this.next = next;
}
}
-
TLinkedList 类:
- 实现了
List
接口,使用泛型来表示列表的元素类型。 - 成员变量包括
root
(链表的头节点)、last
(链表的尾节点)、size
(链表中的元素个数)。
- 实现了
public class TLinkedList<E> implements List{
Node<E> root;
Node<E> last;
int size;
}
-
构造方法:
TLinkedList(E e)
: 接受一个元素作为参数,创建包含该元素的链表。TLinkedList()
: 无参数构造方法,用于创建空链表。
public TLinkedList(E e){
if(e == null){
throw new NullPointerException ("o:" + e);
}
root = new Node<>(e, null);
size++;
}
public TLinkedList(){ }//添加数据
-
主要方法实现:
size()
: 返回链表中的元素个数。
public int size() {
return size;
}
isEmpty()
: 判断链表是否为空。
public boolean isEmpty() {
return size==0;
}
contains(Object o)
: 判断链表是否包含指定元素。
public boolean contains(Object o) {
Node<E> tempNode = root;
while(tempNode != null){
if(tempNode.value == o){
return true;
}else{
tempNode = tempNode.next;
}
}
return false;
}
toArray()
: 将链表转换为数组。
public Object[] toArray() {
Object[] array = new Object[size];
Node<E> tempNode = root;
int index = 0;
while (tempNode != null) {
array[index++] = tempNode.value;
tempNode = tempNode.next;
}
return array;
}
add(Object o)
: 向链表末尾添加元素。
public boolean add(Object o) {
// 判断 root 是否为null
if(root == null){
root = new Node<>( (E)o, null);
size++;
return true;
}
// 循环查找 最后一个节点
// 迭代的思路
Node<E> tempNode = root;
while(tempNode.next != null){
// 替换
tempNode = tempNode.next;
}
//System.out.println ("tempNode:" + tempNode);
tempNode.next = new Node<>((E)o, null);
size++;
return true;
}
remove(Object o)
: 从链表中移除指定元素。
public boolean remove(Object o) {
Node<E> tempNode = root;
// 处理从根节点移除的情况
while (tempNode != null && tempNode.value==o) {
tempNode = tempNode.next;
root = tempNode;
size--;
}
// 处理从链表其余部分移除的情况
while (tempNode != null && tempNode.next != null) {
if (tempNode.next.value==o) {
tempNode.next = tempNode.next.next;
size--;
} else {
tempNode = tempNode.next;
}
}
return true;
}
containsAll(List c)
: 判断链表是否包含另一个集合中的所有元素。
public boolean containsAll(List c) {
for (int i = 0; i < c.size(); i++) {
Object element = c.get(i);
boolean found = false;
Node<E> tempNode = root;
while (tempNode != null) {
if (tempNode.value.equals(element)) {
found = true;
break;
} else {
tempNode = tempNode.next;
}
}
if (!found) {
return false; // 如果任何元素未找到,则返回false
}
}
return true; // 所有元素都找到了
}
addAll(List c)
: 将另一个集合中的所有元素添加到链表末尾。
public boolean addAll(List c) {
for (int i=0 ; i < c.size() ; i++) {
Object element = c.get(i);
// 判断 root 是否为null
if(root == null){
root = new Node<>( (E)element, null);
size++;
}
// 循环查找 最后一个节点
// 迭代的思路
Node<E> tempNode = root;
while(tempNode.next != null){
// 替换
tempNode = tempNode.next;
}
//System.out.println ("tempNode:" + tempNode);
tempNode.next = new Node<>((E)element, null);
size++;
}
return false;
}
addAll(int index, List c)
: 在指定位置插入另一个集合中的所有元素。
public boolean addAll(int index, List c) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
for (int i = 0; i < c.size(); i++) {
Object element = c.get(i);
if (index == 0) {
// 在链表头部插入新节点
root = new Node<>((E) element, root);
} else {
Node<E> tempNode = root;
for (int j = 0; j < index - 1; j++) {
tempNode = tempNode.next;
}
tempNode.next = new Node<>((E) element, tempNode.next);
}
size++;
index++;
}
return true;
}
clear()
: 移除链表中的所有元素。
public void clear() {
Node<E> tempNode = root;
while(tempNode != null){
// 替换
tempNode.value = null;
tempNode = tempNode.next;
}
size = 0;
}
get(int index)
: 获取指定位置的元素。
public Object get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
Node<E> tempNode = root;
for (int i = 0; i < index; i++) {
tempNode = tempNode.next;
}
return tempNode.value;
}
set(int index, Object element)
: 替换指定位置的元素。
public Object set(int index, Object element) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
Node<E> tempNode = root;
for (int j = 0; j < index; j++) {
tempNode = tempNode.next;
}
tempNode.value = (E) element; // 直接更新指定索引处节点的值
return true;
}
add(int index, Object element)
: 在指定位置插入一个元素。
public void add(int index, Object element) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
if (index == 0) {
// 插入到链表头部
root = new Node<>((E) element, root);
} else {
Node<E> tempNode = root;
for (int i = 0; i < index - 1; i++) {
tempNode = tempNode.next;
}
tempNode.next = new Node<>((E) element, tempNode.next);//
}
size++;
}
remove(int index)
: 移除指定位置的元素。
public Object remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
Node<E> tempNode = root;
for (int j = 0; j < index-1; j++) {
tempNode = tempNode.next;
}
tempNode.next=tempNode.next.next;
size--;
return true;
}
indexOf(Object o)
: 获取第一个匹配元素的索引。
public int indexOf(Object o) {
int index=0;
Node<E> tempNode = root;
while(tempNode != null){
if(tempNode.value == o){
return index;
}else{
tempNode = tempNode.next;
index=index+1;
}
}
return -1;
}
removeAll(List c)
: 移除链表中与另一个集合相同的所有元素。
public boolean removeAll(List c) {
boolean modified = false;
for (int i = 0; i < c.size(); i++) {
Object element = c.get(i);
Node<E> tempNode = root;
Node<E> prevNode = null;
while (tempNode != null) {
if (tempNode.value.equals(element)) {
if (prevNode == null) {
// 移除头节点
root = tempNode.next;
} else {
prevNode.next = tempNode.next;
}
size--;
modified = true;
break; // 一旦找到并移除元素,就退出循环
}
prevNode = tempNode;
tempNode = tempNode.next;
}
}
return modified;
}
-
主方法(main):
- 演示对
TLinkedList
对象进行一系列操作的例子,对实现的方法进行测试包括添加、移除、查询等。
- 演示对
public static void main(String[] args) {
TLinkedList<Integer> myLinkList = new TLinkedList<>();
for(int i=1;i<11;i++){
myLinkList.add(i);
}
for(int i=0;i<10;i++){
System.out.println(myLinkList.get(i));
}
//System.out.println(myLinkList.size);
//System.out.println(myLinkList.isEmpty());
//System.out.println(myLinkList.contains(10));
//Object[] array = myLinkList.toArray();
//for (Object element : array) {
//System.out.print(element + " ");
//}
//myLinkList.remove((Integer)5);
//for(int i=0;i<9;i++){
//System.out.println(myLinkList.get(i));
//}
//myLinkList.clear();
//System.out.println(myLinkList.size);
//myLinkList.set(0,11);
//for(int i=0;i<10;i++){
//System.out.println(myLinkList.get(i));
//}
//myLinkList.add(1,12);
//for(int i=0;i<11;i++){
//System.out.println(myLinkList.get(i));
//}
//myLinkList.remove(1);
//for(int i=0;i<9;i++){
//System.out.println(myLinkList.get(i));
//}
//System.out.println(myLinkList.indexOf(5));
TLinkedList<Integer> testList1 = new TLinkedList<>();
testList1.add(8);
testList1.add(9);
testList1.add(10);
TLinkedList<Integer> testList2 = new TLinkedList<>();
testList2.add(11);
testList2.add(12);
testList2.add(13);
for(int i=0;i<3;i++){
//System.out.println(testList1.get(i));
}
for(int i=0;i<3;i++){
//System.out.println(testList2.get(i));
}
//System.out.println(myLinkList.containsAll(testList1));
//System.out.println(myLinkList.containsAll(testList2));
//myLinkList.addAll(testList2);
//for(int i=0;i<13;i++){
//System.out.println(myLinkList.get(i));
//}
//myLinkList.addAll(1,testList2);
//for(int i=0;i<13;i++){
//System.out.println(myLinkList.get(i));
//}
//myLinkList.removeAll(testList1);
//for(int i=0;i<7;i++){
//System.out.println(myLinkList.get(i));
//}
}
链表是一种常见的线性数据结构,具有以下特点:
-
非连续存储: 链表中的元素在内存中可以是不连续存储的,每个元素包含一个数据域和一个指向下一个元素的引用。
-
动态大小: 链表的大小可以动态改变,不像数组有固定的大小。
-
插入和删除高效: 插入和删除操作在链表中相对高效,特别是在中间插入或删除元素,因为不需要移动整个数据结构。
-
随机访问较慢: 相比于数组,链表的随机访问效率较低,需要从头节点开始遍历直到找到目标元素。
-
不浪费内存空间: 链表可以动态分配内存,不需要预先指定固定大小,因此不会浪费内存。
适合执行以下操作:
-
频繁的插入和删除: 由于插入和删除操作在链表中效率较高,链表适合在频繁进行这些操作的场景。
-
不需要随机访问: 如果主要操作是在链表的首部或尾部进行插入、删除等操作,而不需要随机访问元素,链表是一个合适的选择。
-
内存动态分配: 当不知道数据量的大小,或者需要动态分配内存时,链表可以更好地满足需求。
-
不浪费内存空间: 由于链表可以动态调整大小,避免了固定大小数组可能带来的内存浪费。
需要注意的是,链表并不适合需要频繁随机访问元素的情况,因为这时数组更为高效。选择链表还是数组取决于具体的应用场景和操作需求。