1. java单链表中结点类用private修饰,怎么用在链表类里
在Java单链表中,节点类通常包含两个属性:一个存储数据的变量和一个指向下一个节点谈兄皮的变量。为了保证数据的封装性,通常会将这两个属性都用private修饰,然后提供对应的getter和setter方法含差来访问和修改这些属性。
下面是一个简单的Java单链表节点类示例:
public class ListNode {
private int val;
private ListNode next;
public ListNode(int val) {
this.val = val;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
在链表类中,我们需要创建一个头节点来表示整个链表的起始位置。可以将链表类的定义如下:
public class LinkedList {
private ListNode head;
public LinkedList() {
this.head = null;
}
// 添加节点到链表尾部
public void addNode(int val) {
ListNode newNode = new ListNode(val);
if (head == null) {
head = newNode;
} else {
ListNode cur = head;
while (cur.getNext() != null) {
cur = cur.getNext();
}
cur.setNext(newNode);
}
}
// 遍历链表并输出节点值
public void traverse() {
ListNode cur = head;
while (cur != null) {
System.out.print(cur.getVal() + " ");
cur = cur.getNext();
}
System.out.println();
}
}
在链表类中,我们将head属性也用private修饰,并提供对应的getter和setter方法来访问和修改head属性。在addNode方法中,我们首先判断链表是否为空,如果为空,直接将新节点作为头节点;否则,遍历链表找到尾节点并将新节点接在其后面。在traverse方法中,我们遍历整个链表并输出每个节点的值。
使用时,可以创建一个新的LinkedList对象,然后调用其addNode方法添加节点,最后调尘和用traverse方法遍历链表并输出每个节点的值。例如:
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.addNode(1);
list.addNode(2);
list.addNode(3);
list.traverse();
}
这段代码会输出:1 2 3。
2. java怎么用链表实现
在数据结构中经常看见的一个基本概念-链表。
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
在Java中,对于链表的实现都是基于引用数据类型操作的。实现大致如下:
定义节点类Node,节点的概念很重要,一个链表是由各各节点连接在一起组成的。在节点类Node中定义节点内容及指向下一节点的引用,再增加一个添加节点的方法即可完成链表实现。
链表有很多种不同的类型:单向链表,双向链表以及循环链表。在执行效率上,相比数组而言,链表插入快查找慢,开发中得根据实际业务使用。
3. Java语言没有指针,怎样实现链表
Java语言中的对象引用实际上是一个指针(这里的指针均为概念上的意义,而非语言提供的数据类型),所以我们可以编写这样的类来实现链表中的结点。
程序代码:
classNode
{
Objectdata;
Nodenext;//指向下一个结点
}
将数据域定义成Object类是因为Object类是广义超类,任何类对象都可以给其赋值,增加了代码的通用性。为了使链表可以被访问还需要定义一个表头,表头必须包含指向第一个结点的指针和指向当前结点的指针。为了便于在链表尾部增加结点,还可以增加一指向链表尾部的指针,另外还可以用一个域来表示链表的大小,当调用者想得到链表的大小时,不必遍历整个链表。
链表的数据结构我们可以用类List来实现链表结构,用变量Head、Tail、Length、Pointer来实现表头。存储当前结点的指针时有一定的技巧,Pointer并非存储指向当前结点的指针,而是存储指向它的前趋结点的指针,当其值为null时表示当前结点是第一个结点,因为当删除当前结点后仍需保证剩下的结点构成链表,如果Pointer指向当前结点,则会给操作带来很大困难。如何得到当前结点呢?我们定义了一个方法cursor(),返回值是指向当前结点的指针。类List还定义了一些方法来实现对链表的基本操作,通过运用这些基本操作我们可以对链表进行各种操作。例如reset()方法使第一个结点成为当前结点。insert(Object d)方法在当前结点前插入一个结点,并使其成为当前结点。remove()方法删除当前结点同时返回其内容,并使其后继结点成为当前结点,如果删除的是最后一个结点,则第一个结点变为当前结点。
链表类List的源代码如下:
packagecn.javatx;importjava.io.IOException;/**
*@authorljfan
*
*/
publicclassList{
privateNodeHead=null;
privateNodeTail=null;
privateNodePointer=null;
privateintLength=0;publicvoiddeleteAll(){
Head=null;
Tail=null;
Pointer=null;
Length=0;
}publicvoidreset(){
Pointer=null;
}publicbooleanisEmpty(){
return(Length==0);
}publicbooleanisEnd(){
if(Length==0)
thrownewjava.lang.NullPointerException();
elseif(Length==1)
returntrue;
else
return(cursor()==Tail);
}publicObjectnextNode(){
if(Length==1)
thrownewjava.util.NoSuchElementException();
elseif(Length==0)
thrownewjava.lang.NullPointerException();
else{
Nodetemp=cursor();
Pointer=temp;
if(temp!=Tail)
return(temp.next.data);
else
thrownewjava.util.NoSuchElementException();
}
}publicObjectcurrentNode(){
Nodetemp=cursor();
returntemp.data;
}publicvoidinsert(Objectd){
Nodee=newNode(d);
if(Length==0){
Tail=e;
Head=e;
}else{
Nodetemp=cursor();
e.next=temp;
if(Pointer==null)
Head=e;
else
Pointer.next=e;
}
Length++;
}publicintsize(){
return(Length);
}publicObjectremove(){
Objecttemp;
if(Length==0)
thrownewjava.util.NoSuchElementException();
elseif(Length==1){
temp=Head.data;
deleteAll();
}else{
Nodecur=cursor();
temp=cur.data;
if(cur==Head)
Head=cur.next;
elseif(cur==Tail){
Pointer.next=null;
Tail=Pointer;
reset();
}else
Pointer.next=cur.next;
Length--;
}
returntemp;
}privateNodecursor(){
if(Head==null)
thrownewjava.lang.NullPointerException();
elseif(Pointer==null)
returnHead;
else
returnPointer.next;
}publicstaticvoidmain(String[]args){
Lista=newList();
for(inti=1;i<=10;i++)
a.insert(newInteger(i));
System.out.println(a.currentNode());
while(!a.isEnd())
System.out.println(a.nextNode());
a.reset();
while(!a.isEnd()){
a.remove();
}
a.remove();
a.reset();
if(a.isEmpty())
System.out.println("ThereisnoNodeinListn");
System.out.println("Youcanpressreturntoquitn");
try{
System.in.read();
}catch(IOExceptione){
}
}
}classNode{
Objectdata;
Nodenext;Node(Objectd){
data=d;
next=null;
}
}
当然,双向链表基本操作的实现略有不同。链表和双向链表的实现方法,也可以用在堆栈和队列的现实中。
4. Java链表ListNode的理解与操作技巧
深入理解Java链表——ListNode的奥秘与高效操作
链表,这位数据结构的低调明星,与数组并肩存在,但实现原理却大相径庭。Java中,ArrayList依托数组,而LinkedList则依托链表。链表的一大优势在于数据的动态添加和删除,但循环遍历效率却不如数组。它是一个由节点(Node)串联而成的线性结构,内存中的数据分布不连续,每个节点持有自己的数据和对下一个节点的引用,形成了链式连接。链表的主角——单向链表,仅有一个头节点(Head),所有的操作都是通过它进行的,无论是插入还是删除。
想象一下,就像一个看不见的线索,每个节点都持有指向下一个节点的线索,上图中,头节点就像这个链条的起点。有趣的是,添加节点的过程却从链尾开始,新节点被插入到当前尾节点之后,形成一个不断扩展的序列。每个节点都仅知道自己下一个节点的位置,这就是链表的魅力所在。
节点的构造精巧,由对象值(val或data)和指向下一个节点的引用(Node.next)构成,就像一个信息传递的接力赛,每个节点都承载着数据和传递的使命。以下是ListNode的精简版定义:
在MyList类中,链表的操作方法更是精细入微。添加节点(add)、删除指定节点(delete)、获取节点长度(size)、查找节点位置(find),以及通过下标获取节点(get),每个方法都展示了链表操作的灵活性和高效性。比如,delete方法通过遍历链表找到目标节点,然后更新节点连接,避免了数组需要移动大量元素的麻烦。
最后,别忘了链表还有个华丽转身的时刻——链表反转(reverse)。通过交换每个节点的前后节点,链表从头到尾的顺序来了个180度的大转弯,展示了链表操作的多样性和可能性。
链表,这个看似平凡的数据结构,实则蕴含着丰富的操作技巧和灵活性。通过熟练掌握ListNode,你将能在Java编程世界中游刃有余地处理各种数据操作,让代码更加高效且优雅。
5. 用JAVA语言,编写一个链表类(双向链表),实现插入,删除,查找操作。新手,要俗易懂些,最好自己调适通过。急
定义接口:
//Deque.java
package dsa; //根据自己的程序位置不同
public interface Deque {
public int getSize();//返回队列中元素数目
public boolean isEmpty();//判断队列是否为空
public Object first() throws ExceptionQueueEmpty;//取首元素(但不删除)
public Object last() throws ExceptionQueueEmpty;//取末元素(但不删除)
public void insertFirst(Object obj);//将新元素作为首元素插入
public void insertLast(Object obj);//将新元素作为末元素插入
public Object removeFirst() throws ExceptionQueueEmpty;//删除首元素
public Object removeLast() throws ExceptionQueueEmpty;//删除末元素
public void Traversal();//遍历
}
双向链表实现:
//Deque_DLNode.java
/*
* 基于双向链表实现双端队列结构
*/
package dsa;
public class Deque_DLNode implements Deque {
protected DLNode header;//指向头节点(哨兵)
protected DLNode trailer;//指向尾节点(哨兵)
protected int size;//队列中元素的数目
//构造函数
public Deque_DLNode() {
header = new DLNode();
trailer = new DLNode();
header.setNext(trailer);
trailer.setPrev(header);
size = 0;
}
//返回队列中元素数目
public int getSize()
{ return size; }
//判断队列是否为空
public boolean isEmpty()
{ return (0 == size) ? true : false; }
//取首元素(但不删除)
public Object first() throws ExceptionQueueEmpty {
if (isEmpty())
throw new ExceptionQueueEmpty("意外:双端队列为空");
return header.getNext().getElem();
}
//取末元素(但不删除)
public Object last() throws ExceptionQueueEmpty {
if (isEmpty())
throw new ExceptionQueueEmpty("意外:双端队列为空");
return trailer.getPrev().getElem();
}
//在队列前端插入新节点
public void insertFirst(Object obj) {
DLNode second = header.getNext();
DLNode first = new DLNode(obj, header, second);
second.setPrev(first);
header.setNext(first);
size++;
}
//在队列后端插入新节点
public void insertLast(Object obj) {
DLNode second = trailer.getPrev();
DLNode first = new DLNode(obj, second, trailer);
second.setNext(first);
trailer.setPrev(first);
size++;
}
//删除首节点
public Object removeFirst() throws ExceptionQueueEmpty {
if (isEmpty())
throw new ExceptionQueueEmpty("意外:双端队列为空");
DLNode first = header.getNext();
DLNode second = first.getNext();
Object obj = first.getElem();
header.setNext(second);
second.setPrev(header);
size--;
return(obj);
}
//删除末节点
public Object removeLast() throws ExceptionQueueEmpty {
if (isEmpty())
throw new ExceptionQueueEmpty("意外:双端队列为空");
DLNode first = trailer.getPrev();
DLNode second = first.getPrev();
Object obj = first.getElem();
trailer.setPrev(second);
second.setNext(trailer);
size--;
return(obj);
}
//遍历
public void Traversal() {
DLNode p = header.getNext();
while (p != trailer) {
System.out.print(p.getElem()+" ");
p = p.getNext();
}
System.out.println();
}
}
6. Java中ArrayList、LinkedList、Vector、Stack的比较
一、介绍
在Java中,ArrayList、LinkedList、Vector和Stack都是List接口的实现类。它们各自有独特的特性和性能特点。
ArrayList基于动态数组实现,提供快速的随机访问,但插入和删除操作效率较低。
LinkedList采用双向链表结构,适合进行插入和删除操作,但随机访问效率较低。
Vector类似于ArrayList,但实现了线程安全,因此在多线程环境中有较好的表现,但性能不如ArrayList。
Stack继承自Vector,遵循先进后出原则(FILO)。
二、性能测试与分析
通过性能测试,可以看出不同类在读取、插入和删除操作上的效率差异。
读取操作:ArrayList > Vector > Stack > LinkedList
插入操作:LinkedList > Vector > ArrayList > Stack
删除操作:LinkedList > Vector > ArrayList > Stack
三、插入操作分析
在插入元素时,LinkedList需在链表中查找指定位置并插入新节点,而ArrayList则通过复制部分数组来实现,Vector也采用类似方式。
四、查找操作分析
LinkedList和ArrayList的查找操作略有不同:LinkedList需在链表中定位元素,而ArrayList则能直接访问数组中的元素。
五、删除操作分析
删除操作中,LinkedList的效率较高,因为它仅需调整前后指针,而无需移动大量数据。
六、结论
在不同操作场景下,选择合适的数据结构至关重要。通常情况下,
读取操作推荐使用ArrayList,插入操作推荐使用LinkedList,单线程环境下可选择Vector,而Stack适用于遵循FILO原则的场景。