线性表的Java实现--链式存储(单向链表)
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。
链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素。由于不需要按顺序存储,链表在插入、删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢。
使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理。但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空间开销较大。
下图就是最简单最一般的单向链表:
新增节点:
将值为element的新节点插入到第index的位置上。
首先要先找到索引为index-1的节点,然后生成一个数据为element的新节点newNode,并令index-1处节点的next指向新节点,新节点的next指向原来index处的节点。
删除节点:
删除第index个节点,第index节点是由index-1出的节点引用的,因此删除index的节点要先获取index-1处的节点,然后让index-1出节点的next引用到原index+1处的节点,并释放index处节点即可。
单向链表的Java实现
下面的程序分别实现了线性表的初始化、获取线性表长度、获取指定索引处元素、根据值查找、插入、删除、清空等操作。
package com.liuhao.algorithm; public class LinkList<T> { // 定义一个内部类Node,代表链表的节点 private class Node { private T data;// 保存数据 private Node next;// 指向下个节点的引用 // 无参构造器 public Node() { } // 初始化全部属性的构造器 public Node(T data, Node next) { this.data = data; this.next = next; } } private Node header;// 保存头结点 private Node tail;// 保存尾节点 private int size;// 保存已含有的节点数 // 创建空链表 public LinkList() { header = null; tail = null; } // 已指定数据元素创建链表,只有一个元素 public LinkList(T element) { header = new Node(element, null); // 只有一个节点,header,tail都指向该节点 tail = header; size++; } // 返回链表的长度 public int length() { return size; } // 获取指定索引处的元素 public T get(int index) { return this.getNodeByIndex(index).data; } //获取指定位置的节点 private Node getNodeByIndex(int index){ if(index < 0 || index > size-1){ throw new IndexOutOfBoundsException("索引超出线性表范围"); } Node current = header;//从header开始遍历 for(int i=0; i<size && current!=null; i++,current=current.next){ if(i == index){ return current; } } return null; } //按值查找所在位置 public int locate(T element){ Node current = header; for(int i=0; i<size && current!=null; i++, current=current.next){ if(current.data.equals(element)){ return i; } } return -1; } //指定位置插入元素 public void insert(T element, int index){ if(index < 0 || index > size){ throw new IndexOutOfBoundsException("索引超出线性表范围"); } //如果是空链表 if(header == null){ add(element); } else{ //当index为0时,即在链表头处插入 if(0 == index){ addAtHead(element); } else{ Node prev = getNodeByIndex(index - 1);//获取前一个节点 //让prev的next指向新节点,新节点的next指向原来prev的下一个节点 prev.next = new Node(element, prev.next); size++; } } } //在尾部插入元素 public void add(T element) { //如果链表是空的 if(header == null){ header = new Node(element, null); //只有一个节点,headwe,tail都该指向该节点 tail = header; } else{ Node newNode = new Node(element, null);//创建新节点 tail.next = newNode;//尾节点的next指向新节点 tail = newNode;//将新节点作为尾节点 } size++; } //头部插入 public void addAtHead(T element){ //创建新节点,让新节点的next指向header //并以新节点作为新的header Node newNode = new Node(element, null); newNode.next = header; header = newNode; //若插入前是空表 if(tail == null){ tail = header; } size++; } //删除指定索引处的元素 public T delete(int index){ if(index < 0 || index > size-1){ throw new IndexOutOfBoundsException("索引超出线性表范围"); } Node del = null; //若要删除的是头节点 if(index == 0){ del = header; header = header.next; } else{ Node prev = getNodeByIndex(index - 1);//获取待删除节点的前一个节点 del = prev.next;//获取待删除节点 prev.next = del.next; del.next = null;//将被删除节点的next引用置为空 } size--; return del.data; } //删除最后一个元素 public T remove(){ return delete(size - 1); } //判断线性表是否为空 public boolean isEmpty(){ return size == 0; } //清空线性表 public void clear(){ //将header,tail置为null header = null; tail = null; size = 0; } public String toString(){ if(isEmpty()){ return "[]"; } else{ StringBuilder sb = new StringBuilder("["); for(Node current = header; current != null; current = current.next){ sb.append(current.data.toString() + ", "); } int len = sb.length(); return sb.delete(len-2, len).append("]").toString(); } } }
测试代码
package com.liuhao.test; import org.junit.Test; import com.liuhao.algorithm.LinkList; public class LinkListTest { @Test public void test() { // 测试构造函数 LinkList<String> list = new LinkList("好"); System.out.println(list); // 测试添加元素 list.add("ni"); list.add("没"); System.out.println(list); // 在头部添加 list.addAtHead("五月"); System.out.println(list); // 在指定位置添加 list.insert("摩卡", 2); System.out.println(list); // 获取指定位置处的元素 System.out.println("第2个元素是(从0开始计数):" + list.get(2)); // 返回元素索引 System.out.println("摩卡在的位置是:" + list.locate("摩卡")); System.out.println("moka所在的位置:" + list.locate("moka")); // 获取长度 System.out.println("当前线性表的长度:" + list.length()); // 判断是否为空 System.out.println(list.isEmpty()); // 删除最后一个元素 list.remove(); System.out.println("调用remove()后:" + list); // 获取长度 System.out.println("当前线性表的长度:" + list.length()); // 删除指定位置处元素 list.delete(3); System.out.println("删除第4个元素后:" + list); // 获取长度 System.out.println("当前线性表的长度:" + list.length()); // 清空 list.clear(); System.out.println(list); // 判断是否为空 System.out.println(list.isEmpty()); } }
代码获取地址:https://github.com/liuhao123/JavaMore.git
相关推荐
总结,"线性表实现源码-java"涉及到Java中对线性表两种常见存储结构——顺序存储(ArrayList)和链式存储(LinkedList)的实现,以及相关的基本操作。这些源码对于学习和理解数据结构及其在Java中的应用具有重要意义...
在计算机科学中,线性表可以采用顺序存储结构或链式存储结构来实现。本篇主要讨论的是链式存储结构的线性表,也就是链表。 链表是一种动态数据结构,它的优点在于内存分配是按需进行的,即每个节点只在需要时才被...
在实际应用中,线性表可以采用两种不同的存储方式:顺序存储和链式存储。本篇主要讨论的是链式存储,特别是链表这一实现方式。 链表是一种动态数据结构,它的特点是元素(也称为节点)在内存中不是连续存放的,而是...
#### 链表存储结构详解 - **链表定义**:链表由一系列结点组成,每个结点包含一个整型数据域`nNumber`和一个指向下一个结点的指针`next`。 - **链表创建**:通过函数`LinkList createLink()`实现。该函数负责读取...
线性表有两种主要的存储方式:顺序存储和链式存储。 2.1 顺序存储结构 - 顺序表: 顺序表是线性表的顺序存储结构,它使用一块连续的内存空间来存储表中的元素。这种结构的特点包括: - 容量固定:在创建时需要预先...
双向链表是一种链式存储结构,与单向链表不同,每个节点不仅包含数据,还包含两个指针,一个指向其前一个节点,另一个指向其后一个节点。这种设计使得在链表中的前向和后向移动都变得非常高效。 在双向链表中,节点...
在实现上,线性表可以采用顺序存储或链式存储两种方式。顺序存储通常使用数组,数据元素在内存中是连续存放的,可以通过下标快速访问;链式存储则使用链表,每个元素(节点)包含数据域和指针域,指针指向下一个元素...
单向链表是一种单向链式的存储结构,每个数据元素都带有一个指向下一个数据元素的指针。循环链表是一种特殊的链表,最后一个数据元素的指针指向第一个数据元素,形成一个闭合的链式结构。双向循环链表是一种特殊的...
1. **链表数据结构**:实验中使用了单向链表来存储多项式的系数和指数。链表是一种非连续的存储结构,每个节点包含数据元素和指向下一个节点的指针。在这个实验中,链表的节点包含了系数(co)和指数(ex),并且...
同时,PPT提到了单链表类SinglyLinkedList,它使用单向链表实现线性表,每个节点包含数据和指向下一个节点的引用。 链表的插入和删除操作涉及到对指针的修改,这是链式存储结构的一个难点。单链表只能向前遍历,而...
带头结点的单向链式线性表,实现遍历,插入,删除,按序插入,清空
线性链表分为单向链表和双向链表,其中单向链表的每个节点只包含一个指向其后继节点的指针,而双向链表的每个节点包含两个指针,分别指向其前驱和后继节点。 ### 三、线性表的应用案例 线性表在实际应用中有广泛的...
本实验的目标是理解和熟练掌握线性表的逻辑结构以及链式存储结构,并能够实现单链表的基本操作,如插入、查找和删除等。 链式存储结构与顺序存储结构不同,它不依赖于内存中的连续空间。线性表的链式存储通常采用...
实验中采用的是单向链表,这种链表的每个结点包含数据和指向下一个结点的指针。 实验的具体实现如下: 1. **结构定义**:首先,定义了一个结构体`PW`来存储评委的信息,包括姓名、年龄和评分。结构体中还包含一个...
包含单向链表的插入,删除,遍历 含有前插法,尾插法等链表操作 适用于数据结构初学者使用 线性表的单链表存储结构,整个链表的存取必须从头指针开始进行,头指针指示链表中第一个结点 (第一个数据元素的存储映像,...
在本实验中,线性表的链式存储结构是通过链表来实现的,链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 1. 链表的概念与结构: 链表由一系列节点组成...
本实验报告涉及的主要知识点是数据结构中的线性表和链式存储结构,以及C++编程语言的应用。具体来说,以下是一些关键概念和技术: 1. **线性表**:线性表是一种基本的数据结构,由有限个相同类型元素构成的有序序列...
本文主要涉及的是数据结构中的线性表及其链式存储结构,具体是针对一个评委打分的单向链表的操作。实验的主要目的是掌握线性表的链式存储结构,理解顺序表的基本特性,并通过实践加深对链表操作的理解。 1. **链表...
- **循环链表的应用**:约瑟夫环问题是一种著名的算法问题,选题4中要求用单向循环链表实现。这个问题涉及到从一个循环链表中按照特定规则(例如,每隔一定数量的节点删除一个节点)删除节点,直至链表只剩下一个...