链表是一种重要的数据结构,在程序设计中占有很重要的地位。链表包括单向链表,双向链表和循环链表。Java语言中的对象引用实际上是一个指针(本文中的指针均为概念上的意义,而非语言提供的数据类型),所以我们可以编写这样的类来实现链表中的结点。
class Node (双向链表)
{
Object data;
Node previous;//指向上一个结点
Node next;//指向下一个结点
}
将数据域定义成Object类是因为Object类是广义超类,任何类对象都可以给其赋值,增加了代码的通用性。为了使链表可以被访问还需要定义一个表头,表头必须包含指向第一个结点的指针和指向当前结点的指针。为了便于在链表尾部增加结点,还可以增加一指向链表尾部的指针,另外还可以用一个域来表示链表的大小,当调用者想得到链表的大小时,不必遍历整个链表。
链表的数据结构:
我们可以用类List来实现链表结构,用变量Head、Tail、Length、Pointer来实现表头。存储当前结点的指针时有一定的技巧,Pointer并非存储指向当前结点的指针,而是存储指向它的前趋结点的指针,当其值为null时表示当前结点是第一个结点。那么为什么要这样做呢?这是因为当删除当前结点后仍需保证剩下的结点构成链表,如果Pointer指向当前结点,则会给操作带来很大困难。那么如何得到当前结点呢,我们定义了一个方法cursor(),返回值是指向当前结点的指针。类List还定义了一些方法来实现对链表的基本操作,通过运用这些基本操作我们可以对链表进行各种操作。例如reset()方法使第一个结点成为当前结点。insert(Object d)方法在当前结点前插入一个结点,并使其成为当前结点。remove()方法删除当前结点同时返回其内容,并使其后继结点成为当前结点,如果删除的是最后一个结点,则第一个结点变为当前结点。
链表类List的源代码如下:
import java.io.*;
public class List
{
/*用变量来实现表头*/
private Node Head=null;
private Node Tail=null;
private Node Pointer=null;
private int Length=0;
public void deleteAll()
/*清空整个链表*/
{
Head=null;
Tail=null;
Pointer=null;
Length=0;
}
public void reset()
/*链表复位,使第一个结点成为当前结点*/
{
Pointer=null;
}
public boolean isEmpty()
/*判断链表是否为空*/
{
return(Length==0);
}
public boolean isEnd()
/*判断当前结点是否为最后一个结点*/
{
if(Length==0)
throw new java.lang.NullPointerException();
else if(Length==1)
return true;
else
return(cursor()==Tail);
}
public Object nextNode()
/*返回当前结点的下一个结点的值,并使其成为当前结点*/
{
if(Length==1)
throw new java.util.NoSuchElementException();
else if(Length==0)
throw new java.lang.NullPointerException();
else
{
Node temp=cursor();
Pointer=temp;
if(temp!=Tail)
return(temp.next.data);
else
throw new java.util.NoSuchElementException();
}
}
public Object currentNode()
/*返回当前结点的值*/
{
Node temp=cursor();
return temp.data;
}
public void insert(Object d)
/*在当前结点前插入一个结点,并使其成为当前结点*/
{
Node e=new Node(d);
if(Length==0)
{
Tail=e;
Head=e;
}
else
{
Node temp=cursor();
e.next=temp;
if(Pointer==null)
Head=e;
else
Pointer.next=e;
}
Length++;
}
public int size()
/*返回链表的大小*/
{
return (Length);
}
public Object remove()
/*将当前结点移出链表,下一个结点成为当前结点,如果移出的结点是最后一个结点,则第一个结点成为当前结点*/
{
Object temp;
if(Length==0)
throw new java.util.NoSuchElementException();
else if(Length==1)
{
temp=Head.data;
deleteAll();
}
练习:
package Link;
/**
* 节点接口
*
* 要求:
* 1.实现下边所有的方法
* 2.根据链表中存储的数据进行排序(比如学生根据学分)
* 3.单链表、双链表、循环链表都实现一遍
* 4.链表总结
*/
public interface NodeLinkedListInterface {
/**
* 添加节点的方法
*
* @param node新添加的节点对象
*/
public abstract void add(Node node);
/**
* 在指定索引位置添加新节点
* @param node要添加的新节点
* @param index指定的索引位置
*/
public abstract void add(Node node, int index);
/**
* 移除指定的节点
* @param node要被移除的节点对象
* @return 返回true和false,true表示移除成功,false表示移除失败
*/
public abstract boolean remove(Node node);
/**
* 移除指定所以位置的节点
* @param index指定要移除的节点索引
* @return 返回true和false,true表示移除成功,false表示移除失败
*/
public abstract boolean remove(int index);
/**
* 获取指定索引位置的节点对象
*
* @param index指定的索引位置
* @return 返回节点对象,如果index的范围超出size,则返回null.
*/
public abstract Node get(int index);
/**
* 获取双链表中存储的元素总数
*
* @return 返回size的值,如果为0则表示链表中没有节点
*/
public abstract int size();
}
package Link;
public class NodeLinkedList
implements NodeLinkedListInterface {//接口
private int size=0;//节点总数
private Node root=null;//根节点
private Node last=null;//尾节点
@Override
public void add(Node node) {
if(null==root){
//让根节点和尾节点都指向新添加的节点
root=node;
last=node;
}else{
//向尾节点添加节点
last.setNext(node);
//将设为上一个节点
node.setPrevious(last);
last=node;
}
size++;
}
@Override
public void add(Node node, int index) {
if(size<index||index<0){
System.out.println("下标越界");
}else{
Node newnode=get(index);
if(index==0){
//如果链表没有结点
root=node;
}else{
//得到上一个结点
Node pnode=newnode.getPrevious();
//设置新的引用关系
pnode.setNext(node);
node.setPrevious(pnode);
}
//设置新的引用关系
node.setNext(newnode);
newnode.setPrevious(node);
}
size++;
}
@Override
public Node get(int index) {
//超出索引,返回null
if(index>=size||index<0){
return null;
}
//让node为根节点
Node node=root;
//遍历至索引位置
for(int i=0;i<index;i++){
//获取node节点的下一个
node=node.getNext();
}
return node;
}
@Override
public boolean remove(Node node) {
int I =0;
for(int i=0;i<size;i++){
Node nodenow = get(i);
if(nodenow==node){
I = i;
}
}
//得到当前索引位置的节点
Node nodenow = get(I);
//得到父节点
Node Fnode = nodenow.getPrevious();
//得到子节点
Node Cnode = nodenow.getNext();
if(Fnode==null){
root=Cnode;
}else if(Cnode==null){
Fnode.setNext(null);
}else{
Fnode.setNext(Cnode);
Cnode.setPrevious(Fnode);
}
size--;
return true;
}
@Override
public boolean remove(int index) {
if(index<0||index>=size){
return false;
}else{
//得到当前索引位置的结点
Node node=get(index);
//得到上一个结点
Node pnode=node.getPrevious();
//得到下一个结点
Node nnode=node.getNext();
if(pnode==null){
root=nnode;
}else if(nnode==null){
pnode.setNext(null);
}else{
pnode.setNext(nnode);
nnode.setPrevious(pnode);
}
size--;
return true;
}
}
@Override
public int size() {
return size;
}
}
package Link;
/**
* 节点类
* @author Sara
*
*/
public class Node {
//节点数据
private int data;
private Node next;
private Node previous;
public Node(){
}
public Node(int data){
this.data=data;
}
public Node(int data,Node next,Node previous){
this.data=data;
this.next=next;
this.previous=previous;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public Node getPrevious() {
return previous;
}
public void setPrevious(Node previous) {
this.previous = previous;
}
}
package Link;
import java.util.Random;
public class Manager {
/**
* @param args
*/
public static void main(String[] args) {
NodeLinkedListInterface nll = new NodeLinkedList();
Random rand = new Random();
for(int i=0;i<10;i++){
Node node = new Node(rand.nextInt(100));
nll.add(node);
}
Node node = new Node(89);
nll.add(node, 5);
for(int i=0;i<nll.size();i++){
if(i==5){
Node node1 = nll.get(i);
System.out.print("new "+node1.getData()+" ");
}else
{
Node node1 = nll.get(i);
System.out.print(node1.getData()+" ");
}
}
System.out.println(" ");
nll.remove(6);
for(int i=0;i<nll.size();i++){
if(i==6){
Node node1 = nll.get(i);
System.out.print("该处删除"+" "+node1.getData()+" ");
}else
{
Node node1 = nll.get(i);
System.out.print(node1.getData()+" ");
}
}
System.out.println(" ");
System.out.println("移除的是第" + (6) + "个节点");
nll.remove(nll.get(5));
for (int i = 0; i < nll.size(); i++) {
Node node2 = nll.get(i);
System.out.print(node2.getData() + " ");
}
for (int i = 1; i < nll.size(); i++) {
for (int j = i; j > 0; j--) {
if (nll.get(j).getData() < nll.get(j - 1).getData()) {
int temp = nll.get(j).getData();
nll.get(j).setData(nll.get(j - 1).getData());
nll.get(j - 1).setData(temp);
}
}
}
System.out.println("");
System.out.println("从小到大排序后的结果为:");
for (int k = 0; k < nll.size(); k++) {
Node nodex = nll.get(k);
System.out.print(nodex.getData()+" ");
}
}
}
分享到:
相关推荐
本项目是关于“用链表实现集合并集”的C++课程设计,主要目的是掌握集合操作以及如何利用链表数据结构高效地实现这些操作。 首先,我们需要了解集合的基本概念。集合是一个无序且不包含重复元素的数学结构。在...
总的来说,C++中链表实现一元多项式的加法是一种巧妙而实用的方法,它结合了数据结构和算法的知识,展示了计算机科学的魅力。通过熟练掌握这样的编程技巧,不仅可以提高编程能力,还能为解决更复杂的问题打下坚实的...
综上所述,用链表实现STM32的多级菜单是一个涉及数据结构、内存管理、事件处理和用户界面设计等多个方面的综合性任务。通过熟练掌握这些知识点,我们可以创建出高效、易用且可扩展的嵌入式系统用户界面。
本项目以"用数据结构-链表实现通讯录管理系统"为主题,通过C语言实现了这一功能,旨在帮助用户管理他们的联系人信息。下面我们将深入探讨这个系统所涉及的主要知识点。 首先,我们来了解**链表**这一数据结构。链表...
链表实现集合运算 链表实现集合交并差运算
### 使用链表实现图书管理系统的知识点 #### 一、链表基本概念 链表是一种常见的数据结构,由一系列节点组成,每个节点包含实际存储的数据和一个指向下一个节点的引用(指针)。在本例中,链表用于实现图书管理系统...
链表实现线性表的基本操作包括添加元素(插入)、删除元素、查找元素以及遍历等。在`ChainList.java`文件中,可能会定义一个名为`Node`的类来表示链表节点,如下所示: ```java class Node { int data; Node next...
### 题目:C语言链表实现学生信息管理 #### 描述: 这是一个用C语言编写的简单程序,通过链表技术实现了学生信息的管理功能。用户可以通过简单的命令行界面执行各种操作,如添加、删除、修改、查询学生信息以及保存...
《C语言学生考试系统——链表实现》 在信息技术领域,C语言作为一种基础且强大的编程语言,被广泛用于系统编程、软件开发以及教学实训。本项目“C语言学生考试系统”便是利用C语言来实现的一个简易考试管理工具,其...
本文将深入探讨Go语言中的双链表实现,以标题"Go-LinkedList一个简单的双链表实现"为例,我们将分析双链表的设计、操作以及其在实际应用中的价值。 双链表是一种线性数据结构,每个节点包含两个指针,分别指向前后...
在"delimetermach.cpp"这个源代码文件中,很可能包含了具体的链表实现栈和队列的C++代码。通过阅读和分析这段代码,我们可以深入理解如何使用C++的指针和结构体来构建链表节点,以及如何通过指针操作来实现栈的压栈...
大学期间用C语言链表实现的一个图书管理系统,主要功能有 a. 设备申请。由专业人员填写“申请表”送交领导批准购买。 b. 设备入库。新设备购入后要立即进行设备登记(包括类别、设备名、型号、规格、单价、数量、...
《航空订票系统--链表实现》 在IT行业中,航空订票系统是航空公司和旅行代理机构的关键组成部分,它负责管理航班信息、座位预订、乘客信息等重要数据。本项目着重探讨了如何利用链表这一数据结构来实现航空订票系统...
通用链表实现是解决这个问题的一种高效方法,它能够处理任意长度的整数,不受固定大小数据类型的限制。本篇文章将深入探讨如何利用链表结构来实现大数相乘,并分析其工作原理和优化策略。 首先,链表是一种动态数据...
5. **优缺点**:链表实现队列时,入队和出队操作通常较快,因为无需移动其他元素。但相比于数组,链表的随机访问性能较差,因为需要遍历找到特定位置的节点。 **对比与选择** 数组和链表实现队列各有优势,具体...
总结,C#版的双向链表实现涉及到泛型、接口和类设计等多个核心编程概念。通过这些工具,我们可以创建一个灵活、高效且可复用的数据结构,以满足各种程序需求。在实际开发中,理解和掌握这些概念对于提升代码质量至关...
在链表实现中,可以考虑结合这两种方法,为不同的查询场景提供优化。 密码退格功能是指用户在输入密码时能撤销最近一次输入的操作。在链表实现中,可以维护一个额外的链表,用于存储用户的输入历史,每次退格操作就...
C语言链表实现单词本管理 本文档主要介绍了使用C语言实现单词本管理系统的设计和实现过程。该系统使用链表结构来存储单词及其对应的中文解释,并提供了插入、删除、查找和输出单词的功能。 1. 链表结构的实现 在...
总的来说,用链表实现多项式运算是一种灵活且高效的方法,它可以方便地处理任意大小的多项式,并支持各种算术操作。链表的动态特性使得这种实现方式具有很高的可扩展性,可以适应不同的问题需求。
本文将深入探讨一种利用链表实现长整型相乘的算法。 链表是一种线性数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的引用。这种数据结构特别适合存储动态增长的序列,因为可以在运行时轻松添加或...