Java实现数据结构线性表和链表
1、首先定义接口
/** * 线性表接口 * @param <T> 元素类型 */ public interface LinearList<T> { /** * 添加元素到表尾 * @param element 要添加的元素 * @return 是否添加成功 */ boolean add(T element); /** * 在指定位置插入元素 * @param index 插入位置 * @param element 要插入的元素 * @return 是否插入成功 */ boolean add(int index, T element); /** * 删除指定位置的元素 * @param index 要删除的位置 * @return 被删除的元素 */ T remove(int index); /** * 删除指定元素 * @param element 要删除的元素 * @return 是否删除成功 */ boolean remove(T element); /** * 获取指定位置的元素 * @param index 位置 * @return 该位置的元素 */ T get(int index); /** * 修改指定位置的元素 * @param index 位置 * @param element 新元素 * @return 原元素 */ T set(int index, T element); /** * 查找元素的位置 * @param element 要查找的元素 * @return 元素的位置,不存在返回-1 */ int indexOf(T element); /** * 检查线性表是否包含指定元素 * @param element 要检查的元素 * @return 是否包含 */ boolean contains(T element); /** * 获取线性表的大小 * @return 元素个数 */ int size(); /** * 检查线性表是否为空 * @return 是否为空 */ boolean isEmpty(); /** * 清空线性表 */ void clear(); /** * 遍历线性表 */ void traverse(); }2、顺序线下表实现
/** * 顺序表实现 * @param <T> 元素类型 */ public class ArrayList<T> implements LinearList<T> { private static final int DEFAULT_CAPACITY = 10; private T[] elements; private int size; @SuppressWarnings("unchecked") public ArrayList() { elements = (T[]) new Object[DEFAULT_CAPACITY]; size = 0; } @SuppressWarnings("unchecked") public ArrayList(int capacity) { if (capacity <= 0) { throw new IllegalArgumentException("容量必须大于0"); } elements = (T[]) new Object[capacity]; size = 0; } @Override public boolean add(T element) { ensureCapacity(); elements[size++] = element; return true; } @Override public boolean add(int index, T element) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException("索引越界:" + index); } ensureCapacity(); // 移动元素 for (int i = size; i > index; i--) { elements[i] = elements[i - 1]; } elements[index] = element; size++; return true; } @Override public T remove(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("索引越界:" + index); } T removed = elements[index]; // 移动元素 for (int i = index; i < size - 1; i++) { elements[i] = elements[i + 1]; } elements[--size] = null; // 避免内存泄漏 return removed; } @Override public boolean remove(T element) { int index = indexOf(element); if (index != -1) { remove(index); return true; } return false; } @Override public T get(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("索引越界:" + index); } return elements[index]; } @Override public T set(int index, T element) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("索引越界:" + index); } T old = elements[index]; elements[index] = element; return old; } @Override public int indexOf(T element) { if (element == null) { for (int i = 0; i < size; i++) { if (elements[i] == null) { return i; } } } else { for (int i = 0; i < size; i++) { if (element.equals(elements[i])) { return i; } } } return -1; } @Override public boolean contains(T element) { return indexOf(element) != -1; } @Override public int size() { return size; } @Override public boolean isEmpty() { return size == 0; } @Override public void clear() { for (int i = 0; i < size; i++) { elements[i] = null; // 避免内存泄漏 } size = 0; } @Override public void traverse() { System.out.print("顺序表: ["); for (int i = 0; i < size; i++) { System.out.print(elements[i]); if (i < size - 1) { System.out.print(", "); } } System.out.println("]"); } /** * 确保容量足够 */ private void ensureCapacity() { if (size >= elements.length) { // 扩容为原来的2倍 @SuppressWarnings("unchecked") T[] newElements = (T[]) new Object[elements.length * 2]; System.arraycopy(elements, 0, newElements, 0, size); elements = newElements; } } }3、链表实现
/** * 链表实现 * @param <T> 元素类型 */ public class LinkedList<T> implements LinearList<T> { private Node<T> head; private int size; private static class Node<T> { T data; Node<T> next; Node(T data) { this.data = data; this.next = null; } } public LinkedList() { head = null; size = 0; } @Override public boolean add(T element) { Node<T> newNode = new Node<>(element); if (head == null) { head = newNode; } else { Node<T> current = head; while (current.next != null) { current = current.next; } current.next = newNode; } size++; return true; } @Override public boolean add(int index, T element) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException("索引越界:" + index); } Node<T> newNode = new Node<>(element); if (index == 0) { newNode.next = head; head = newNode; } else { Node<T> prev = getNode(index - 1); newNode.next = prev.next; prev.next = newNode; } size++; return true; } @Override public T remove(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("索引越界:" + index); } T removed; if (index == 0) { removed = head.data; head = head.next; } else { Node<T> prev = getNode(index - 1); removed = prev.next.data; prev.next = prev.next.next; } size--; return removed; } @Override public boolean remove(T element) { if (head == null) { return false; } if (head.data == null ? element == null : head.data.equals(element)) { head = head.next; size--; return true; } Node<T> prev = head; Node<T> current = head.next; while (current != null) { if (current.data == null ? element == null : current.data.equals(element)) { prev.next = current.next; size--; return true; } prev = current; current = current.next; } return false; } @Override public T get(int index) { return getNode(index).data; } @Override public T set(int index, T element) { Node<T> node = getNode(index); T old = node.data; node.data = element; return old; } @Override public int indexOf(T element) { Node<T> current = head; for (int i = 0; i < size; i++) { if (current.data == null ? element == null : current.data.equals(element)) { return i; } current = current.next; } return -1; } @Override public boolean contains(T element) { return indexOf(element) != -1; } @Override public int size() { return size; } @Override public boolean isEmpty() { return size == 0; } @Override public void clear() { head = null; size = 0; } @Override public void traverse() { System.out.print("链表: ["); Node<T> current = head; while (current != null) { System.out.print(current.data); if (current.next != null) { System.out.print(", "); } current = current.next; } System.out.println("]"); } /** * 获取指定位置的节点 * @param index 位置 * @return 节点 */ private Node<T> getNode(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException("索引越界:" + index); } Node<T> current = head; for (int i = 0; i < index; i++) { current = current.next; } return current; } }4、测试
/** * 线性表测试类 */ public class LinearListTest { public static void main(String[] args) { System.out.println("测试顺序表:"); testLinearList(new ArrayList<>()); System.out.println("\n测试链表:"); testLinearList(new LinkedList<>()); } private static void testLinearList(LinearList<Integer> list) { // 添加元素 list.add(1); list.add(2); list.add(3); list.traverse(); // 在指定位置插入元素 list.add(1, 5); list.traverse(); // 获取元素 System.out.println("索引2的元素:" + list.get(2)); // 修改元素 System.out.println("修改索引1的元素,原元素:" + list.set(1, 6)); list.traverse(); // 查找元素 System.out.println("元素3的位置:" + list.indexOf(3)); System.out.println("是否包含元素6:" + list.contains(6)); // 删除元素 System.out.println("删除索引1的元素:" + list.remove(1)); list.traverse(); // 删除指定元素 System.out.println("删除元素3:" + list.remove(Integer.valueOf(3))); list.traverse(); // 检查大小和是否为空 System.out.println("大小:" + list.size()); System.out.println("是否为空:" + list.isEmpty()); // 清空列表 list.clear(); System.out.println("清空后是否为空:" + list.isEmpty()); list.traverse(); } }实现内容
线性表接口(
LinearList<T>)- 定义了线性表的基本操作方法,如添加、插入、删除、获取、修改、查找等
- 提供了统一的接口,使得顺序表和链表可以通过相同的方式使用
顺序表实现(
ArrayList<T>)- 基于数组实现,支持动态扩容
- 提供了高效的随机访问能力
- 适用于频繁访问元素的场景
链表实现(
LinkedList<T>)- 基于节点实现,每个节点包含数据和指向下一个节点的引用
- 支持高效的插入和删除操作
- 适用于频繁插入和删除元素的场景
测试类(
LinearListTest)- 演示了如何使用顺序表和链表
- 测试了各种操作方法的功能
如何使用
创建线性表实例:
- 顺序表:
LinearList<Integer> arrayList = new ArrayList<>(); - 链表:
LinearList<Integer> linkedList = new LinkedList<>();
- 顺序表:
调用线性表的方法:
- 添加元素:
list.add(1); - 插入元素:
list.add(1, 5); - 删除元素:
list.remove(1); - 获取元素:
list.get(2); - 修改元素:
list.set(1, 6); - 查找元素:
list.indexOf(3); - 遍历元素:
list.traverse();
- 添加元素:
运行测试:
- 执行
LinearListTest类的main方法,查看测试结果
- 执行
代码特点
- 泛型设计:使用泛型使得线性表可以存储任意类型的数据
- 异常处理:对索引越界等情况进行了异常处理
- 内存管理:在顺序表中避免了内存泄漏
- 性能优化:顺序表支持动态扩容,链表提供了高效的插入删除操作
- 代码结构清晰:接口与实现分离,便于维护和扩展
