/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author loan
*/
//整个链表最关心的就是头指针root
class Node{//存放方法靠的是Node对象
private String data;
private Node next; //保存下一个节点
//Node为保存数据而生,这不是简单java类
public Node(String data ){
this.data=data;
}
public void setNext(Node next){
this.next=next;
}
public Node getNext(Node next){
return this.next;
}
public String getData(){
return this.data;
}
//到这目前只是一个专门保存节点的类
//实现节点的添加
//第一次调用(Link): this=Link.root
//第二次调用(Node): this=Link.root.next
//第三次调用(Node): this=Link.root.next.next
//........
public void addNode(Node newNode){
if(this.next==null){ //如果当前节点之后的下一个为null
this.next=newNode;
}
else{//当前结点之后存在节点即存有数据,有指向
this.next.addNode(newNode);//递归判断,一直判断到下一个节点为null时
}
}
//第一次调用(Link):this=Link.root
//第二次调用(Node): this=Link.root.next
//第三次调用(Node): this=Link.root.next.next
//........
public void printNode(){
System.out.println("输出当前节点数据: "+this.data);
if(this.next!=null){
this.next.printNode(); //递归调用
}
}
}
//现在写一个单独的类,负责数据的设置add和输出print,作用: 进行Node类对象关系的处理
class Link{
private Node root;//根节点
public void add(String data){//增加数据,使链表变长
Node newNode=new Node(data);//Node才能够负责先后关系的匹配,所以将data用Node封装
if(this.root==null){//但前根节点为null时
this.root=newNode;
}
else{ //根节点已经存在了该做什么呢??解决下一个节点存入的问题,前面一个节点也许不是头节点,那么就要进行判断(是否为头节点)了
//后面是否有数据应该交由节点来判断
this.root.addNode(newNode);
}
}
public void print(){//输出数据
if(this.root!=null){ //存在根节点
this.root.printNode(); //交给Node类输出
}
}
}
//有一个代表性的东西出现(头节点),其余数据就有路可寻了
//主方法里面不要写太多的细节,因为主方法是客户端,客户端关注的是放的东西取出来,所以客户端至于link类有关-------------主方法:存和取
public class TestDemo3 {
public static void main(String args[]){
Link link=new Link();//此时root还是空的null,创建头指针,创建链表
link.add("Hello");//存入数据
link.add("World");
link.add("loan_chan");
link.add("链表的实现");
link.add("链表画图要比较容易");
link.print();//输出数据
}
}
链表的基本操作特点:
· 客户端代码不用去关注具体的Node以及引用关系的细节,只关注提供的Link类提供的方法配置;
· Link类的主要功能就是控制Node类对象的产生和根节点的使用;
· Node类主要负责数据的保存和以及引用关系的分配。
###这也只是基础的链表,该代码还是存在问题的??###
Node类负责所有节点数据的保存以及节点数据的匹配,所以Node类不可能单独使用。
----------------------------------------------------------------------------------------------------------------------------------------------------------
程序修改后让Node只能被Link类使用,使用内部类可达到此效果,内部类可以用private定义,这样内部类只能被外部类使用,内部类还可以与外部类之间进行私有属性的访问。
空链表的判断有两种方式:
① 判断root是否有对象(是否为null);
② 判断保存的数据量(count)。
任何类都不可能在类中使用输出数据;
链表属于动态对象数组,所以要输出链表中的数据最好就是将链表变为对象数组再以数组的形式输出;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author loan
*/
//这个程序把产生链表的类Node变成了内部类,使其不被外部直接操作
//整个链表最关心的就是头指针root
//现在写一个单独的类,负责数据的设置add和输出print,作用: 进行Node类对象关系的处理
class Link{
//Node此时是内部类,之所一是在内部,主要是让其为Link类服务
class Node{//存放方法靠的是Node对象
private String data;
private Node next; //保存下一个节点
//Node为保存数据而生,这不是简单java类
public Node(String data ){
this.data=data;
}
public void addNode(Node newNode){
if(this.next==null){
this.next = newNode;
} else{
this.next.addNode(newNode);
}
}
//在内部类中进行定义查询
//第一次调用(Link):this=link.root
//第二次调用(nest):this=link.root.next
//......
public boolean containsNode(String data){
if(data.equals(this.data)) return true;
else {
if(this.next != null){
return this.next.containsNode(data); //再一次进行递归操作
}
else return false;
}
}
public String getNode(int index){
if(Link.this.foot ++ == index) return this.data; //这里的this当前变量是Node类,是内部类,所以要外部类.内部类.属性才可以
return this.next.getNode(index);
}
public void setNode(int index,String data){
if (Link.this.foot ++ == index) { this.data=data;}
else{
this.next.setNode(index,data);
}//这里没有返回值,这里如果没有else那么无论if条件成不成立都会执行这里的语句
}
//第一次调用(Link):previous=Link.root.next;
//第二次调用(Node):previous=Link.root.next.next;
//在Node中处理第二种情况,要传递上一个节点以及要删除的数据
public void removeNode(Node previous,String data){
if(this.next.data.equals(data)){
previous.next = this.next;
}
else{
this.next.removeNode(this, data);
}
}
public void toArrayNode(){
Link.this.retArray[Link.this.foot ++] = this.data;
if(this.next != null){
this.next.toArrayNode();
}
}
}
/*==========================================================以上为内部类============================================================*/
//先养成这个习惯有分割线,这样可以使程序容易看
private String [] retArray; //之所以将其定义为属性,是因为内部类与外部类可以相互自由地进行数据访问
private int foot; //会自动增加
private Node root;//根节点
private int count=0;//设置count计数属性,对链表中的元素个数进行计数,这个功能就是public int size()方法
public void add(String data){//增加数据,使链表变长
if(data==null)
return;
Node newNode=new Node(data);//Node才能够负责先后关系的匹配,所以将data用Node封装
if(this.root==null){//但前根节点为null时
this.root=newNode;
}
else{ //根节点已经存在了该做什么呢??解决下一个节点存入的问题,前面一个节点也许不是头节点,那么就要进行判断(是否为头节点)了
//后面是否有数据应该交由节点来判断
//Link类只关注根节点,其他节点交给Node处理
this.root.addNode(newNode);
}
this.count++;
}
public int size(){
return this.count; //取得元素个数的数据
}
public boolean isEmpty(){
return this.count==0;
}
public String get(int index){ //根据索引查询元素
if(index > this.count) return null;
this.foot=0; //从头向后查询
return this.root.getNode(index); //把具体查询的过程交给Node内部类处理
}
public boolean contains(String data){
if(data==null || this.root == null){
return false;
}
return this.root.containsNode(data); //在Node类中从头开始查询
}
public void set(int index,String data ){ //使用新的内容替换掉指定索引的旧的内容
if(index > this.count){ return; } //单纯的只是结束调用方法而已
this.foot=0;
this.root.setNode(index,data);
}
//删除指定数据,如果是对象则要进行对象比较,有两种情况:①删除的是根节点的数据,根节点的下一个节点要变成根节点,在Link中处理 ②删除的是普通节点,在Node类中处理
//当前节点下一节点的next为当前节点的next
public void remove (String data){
if(this.root.data.equals(data)) {
this.root=this.root.next;
}
else{
this.root.next.removeNode(this.root,data);
}
this.count -- ;
}
public String[] toArray(){ //将链表以对象数组的形式返回,且该返回的对象数组要被Node类操作,这样Link类能够访问,Node类也能够访问
if(this.root == null){
return null;
}
this.foot = 0;
this.retArray = new String[this.count];
this.root.toArrayNode();
return this.retArray;
}
}
//有一个代表性的东西出现(头节点),其余数据就有路可寻了
//主方法里面不要写太多的细节,因为主方法是客户端,客户端关注的是放的东西取出来,所以客户端至于link类有关-------------主方法:存和取
public class TestDemo3 {
public static void main(String args[]){
Link link=new Link();//此时root还是空的null,创建头指针,创建链表
System.out.println(link.isEmpty());
link.add("Hello");//存入数据
link.add("World");
link.add("jiaoujiaioo");
link.add("loan_chan");
link.add("链表画图要比较容易");
link.set(1,"-----nihaihaoma-----");
link.remove("Hello");
System.out.println(link.size());//输出数据
System.out.println(link.isEmpty());
System.out.println(link.get(1));
System.out.println(link.get(0));
System.out.println(link.contains("loan_chan"));
System.out.println(link.contains("ooooo")); //如果查询的是一个对象,那就要定义一个对象比较的类,见前面章节
System.out.println();
for(int i=0;i<link.toArray().length;i++){
System.out.println(link.toArray()[i]);
}
}
}
以上是对链表几个常见方法的实践
NO | 方法名称 | 类型 | 功能 |
1 | public void add(数据类型 变量) | 普通 | 向链表中增加新的数据 |
2 | public int size() | 普通 | 取得链表中保存的元素个数 |
3 | public boolean isEmpty() | 普通 | 判断是否是空链表(即size=0) |
4 | public boolean contains(数据类型 变量) | 普通 | 判断某一个数据是否存在 |
5 | public void add(数据类型 变量) | 普通 | 根据索引取得数据 |
6 | public void set(int index,数据类型 变量) | 普通 | 使用新的内容替换掉指定索引的旧的内容 |
7 | public void remove (数据类型 变量) | 普通 | 删除指定数据,如果是对象则要进行对象比较 |
8 | Public 数据类型[] toArray() | 普通 | 将链表变为对象数组 |