链表的基本开发结构
class Link { // 链表类,外部能够看见的只有这一个类
private class Node { // 定义的内部节点类
private String data; // 要保存的数据
private Node next; // 下一个节点引用
public Node(String data) { // 每一个Node类对象都必须保存有相应的数据
this.data = data;
}
}
// ===================== 以上为内部类 ===================
private Node root; // 根节点定义
}
在本结构中将Node定义为了Link的私有内部类,这样做有两个好处:
· Node类只会为Link类服务,并且可以利用Node类匹配节点关系;
· 外部类与内部类之间方便进行私有属性的直接访问,所以不需要在Node类中定义setter、getter方法。
数据增加:public void add(数据类型 变量)
public void add(Stringdata) { //假设不允许有空
if (data == null) { //判断数据是否为空
return ; }
Node newNode = new Node(data); //要保存的数据
if (this.root == null) { //当前没有根节点
this.root = newNode; //保存根节点
} else {
this.root.addNode(newNode); //让node类来处理保存数据
} }
取得保存元素个数: public int size()
privateint count = 0 ; //保存元素的个数
publicint size() { //取得保存的数据量
returnthis.count;
}
判断是否是空链表: public boolean isEmpty ()
/**
* 判断是否是空链表,表示长度为0,不是null
* @return 如果链表中没有保存任何的数据则返回true,否则返回false
*/
public boolean isEmpty() {
return this.count == 0;
}
数据查询:
public
boolean
contains(
数据类型 变量
)
/**
* 数据检索操作,判断指定数据是否存在
* 第一次调用(Link):this = Link.root
* 第二次调用(Node):this = Link.root.next
* @param data 要查询的数据
* @return 如果数据存在返回true,否则返回false
*/
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; // 没有查询到返回false
}
}
}
修改
Link
/**
* 数据查询操作,判断指定数据是否存在,如果链表没有数据直接返回false
* @param data 要判断的数据
* @return 数据存在返回true,否则返回false
*/
public boolean contains(String data) {
if (data == null || this.root == null) { // 现在没有要查询的数据,根节点也不保存数据
return false ; // 没有查询结果
}
return this.root.containsNode(data) ; // 交由Node类查询
}
根据索引取得数据:
public
数据类型
get(
int
index)
在Link类里面增加一个foot的属性,表示每一个Node元素的编号
privateintfoot = 0 ; // 节点索引
在每一次查询的时候(一个链表可能查询多次),那么foot应该在每一次查询时都从头开始计算(foot设为0);
/**
* 根据索引取得保存的节点数据
* @param index 索引数据
* @return 如果要取得的索引内容不存在或者大于保存个数返回null,反之返回数据
*/
public String get(int index) {
if (index > this.count) { // 超过了查询范围
return null ; // 没有数据
}
this.foot = 0 ; // 表示从前向后查询
return this.root.getNode(index) ; // 查询过程交给Node类
}
在
Node
类里面实现
getNode
()
方法
/**
* 根据索引取出数据,此时该索引一定是存在的
* @param index 要取得数据的索引编号
* @return 返回指定索引节点包含的数据
*/
public String getNode(int index) {
// 使用当前的foot内容与要查询的索引进行比较,随后将foot的内容自增,目的是为了下次查询方便
if (Link.this.foot++ == index) { // 当前为要查询的索引
return this.data; // 返回当前节点数据
} else { // 继续向后查询
return this.next.getNode(index); // 进行下一个节点的判断
}
}
修改指定索引内容:
public void set(
int
index,
数据类型 变量
)
/**
* 修改指定索引节点包含的数据
* @param index 要修改的索引编号
* @param data 新数据
*/
public void setNode(int index, String data) {
// 使用当前的foot内容与要查询的索引进行比较,随后将foot的内容自增,目的是为了下次查询方便
if (Link.this.foot++ == index) { // 当前为要修改的索引
this.data = data; // 进行内容的修改
} else {
this.next.setNode(index, data);// 继续下一个节点的索引判断
}
}
在
Link
类里面增加
set()
方法
/**
* 根据索引修改数据
* @param index 要修改数据的索引编号
* @param data 新的数据内容
*/
public void set(int index, String data) {
if (index > this.count) { // 判断是否超过了保存范围
return; // 结束方法调用
}
this.foot = 0; // 重新设置foot属性的内容,作为索引出现
this.root.setNode(index, data); // 交给Node类设置数据内容
}
数据删除:
public void remove(
数据类型 变量
)
情况一:
/**
* 节点的删除操作,匹配每一个节点的数据,如果当前节点数据符合删除数据,
* 则使用“当前节点上一节点.next = 当前节点.next”方式空出当前节点
* 第一次调用(Link),previous = Link.root、this = Link.root.next
* 第二次调用(Node),previous = Link.root.next、this = Link.root.next.next
* @param previous 当前节点的上一个节点
* @param data 要删除的数据
*/
public void removeNode(Node previous, String data) {
if (data.equals(this.data)) { // 当前节点为要删除节点
previous.next = this.next; // 空出当前节点
} else { // 应该向后继续查询
this.next.removeNode(this, data); // 继续下一个判断
}
}
在
Link
类里面增加根节点的判断
/**
* 链表数据的删除操作,在删除前要先使用contains()判断链表中是否存在有指定数据
* 如果要删除的数据存在则首先判断根节点的数据是否为要删除数据
* 如果是则将根节点的下一个节点作为新的根节点
* 如果要删除的数据不是根节点数据,则将删除操作交由Node类的removeNode()方法完成
* @param data 要删除的数据
*/
public void remove(String data) {
if (this.contains(data)) { // 主要功能是判断数据是否存在
// 要删除数据是否是根节点数据,root是Node类的对象,此处直接访问了内部类的私有操作
if (data.equals(this.root.data)) { // 根节点数据为要删除数据
this.root = this.root.next; // 空出当前根节点
} else { // 根节点数据不是要删除数据
// 此时根元素已经判断过了,从第二个元素开始判断,即第二个元素的上一个元素为根节点
this.root.next.removeNode(this.root, data);
}
this.count--; // 删除成功后个数要减少
}
}
将链表变为对象数组:
public
数据类型
[]
toArray
()
修改Link类的定义
增加一个返回的数组属性内容,之所以将其定义为属性,是因为内部类和外部类都可以访问
private String []retArray ; //返回的数组
/**
* 将链表中的数据转换为对象数组输出
* @return 如果链表没有数据返回null,如果有数据则将数据变为对象数组后返回
*/
public String[] toArray() {
if (this.root == null) { // 判断链表是否有数据
return null; // 没有数据返回null
}
this.foot = 0; // 脚标清零操作
this.retArray = new String[this.count]; // 根据保存内容开辟数组
this.root.toArrayNode(); // 交给Node类处理
return this.retArray; // 返回数组对象
}
在
Node
类里面处理数组数据的保存
/**
* 将节点中保存的内容转化为对象数组
* 第一次调用(Link):this = Link.root;
* 第二次调用(Node):this = Link.root.next;
*/
public void toArrayNode() {
Link.this.retArray[Link.this.foot++] = this.data; // 取出数据并保存在数组之中
if (this.next != null) { // 有后续元素
this.next.toArrayNode(); // 继续下一个数据的取得
}
}
清空链表:
public void clear()
public void clear() {
this.root = null; // 清空链表
this.count = 0; // 元素个数为0
}