1.1 认识链表
链表 = 可变长的对象数组,属于动态对象数组的范畴。
传统对象数组:
作用:对象数组可以保存一组对象方便开发。
缺点:对象数组的长度固定,而且数据的修改,删除,增加处理麻烦。
正因为如此,如果想要让其编写出便于维护的代码,那么就需要实现一个动态对象数组,于是可以使用链表完成。
1.2 实现链表
问题:保存数据为了方便使用Object;
数据本身不包含有先后的逻辑关系,所以将数据封装在一个Node类,负责关系的维护。
class Node{//表示定义的节点
private Object data;//表示保存的数据
private Node next;//保存下一个节点
public Node(Object data){//有数据才可以保存节点
this.data=data;
}
public void setNext(Node next){//设置节点
this.next=next;
}
public Node getNext(){//取得节点
return this.next;
}
}
虽然以上的代码已经实现了链的形式,但是实际上Node类对用户没有。所以还需要一个类,这个类可以负责所有Node的关系匹配,而用户只需通过这个类保存数据,取得数据即可。
于是代码变成:
class Node{//表示定义的节点
private Object data;//表示保存的数据
private Node next;//保存下一个节点
public Node(Object data){//有数据才可以保存节点
this.data=data;
}
public void setNext(Node next){//设置节点
this.next=next;
}
public Node getNext(){//取得节点
return this.next;
}
public Object getData(){//取得数据
return this.data;
}
//第一次调用:this=Link.root
//第二次调用:this=Link.root.next
//第三次调用:this=Link.root.next.next
public void addNode(Node newNode){
if(this.next==null){//当前节点后没有节点
this.next=newNode;
}else{//当前节点后有节点
this.next.addNode(newNode);
}
}
public void printNode(){
System.out.println(this.data);
if(this.next!=null){
this.next.printNode();
}
}
}
class Link{//表示一个链表操作类,利用此类来隐藏Node的节点匹配
private Node root;//根元素
public void add(Object obj){//向链表里追加数据
Node newNode = new Node(obj);//将数据包装为Node对象,这样才可以进行先后关系排列
//没有根节点时
if(this.root==null){
this.root=newNode;//第一个节点作为根节点
}else{//根节点存在,交由Node处理
this.root.addNode(newNode);
}
}
public void print(){//输出全部数据
this.root.printNode();
}
}
链表在整个实现过程最关键的就是Node类,Node类要保存数据与下一个节点。
2.1 开发可用链表
以上的代码只能够说是基本的链表形式,可是如何才能实现一个好的链表呢?
1.让Node类只为Link类服务,但是又不让其他类访问。
2.如果要开发程序,那么一定要创建出自己的操作标准,那么一旦说到标准,就应该使用到接口完成。
于是代码结构变成:
interface Link{
}
class LinkImpl implements Link{
private class Node{//使用私有内部类,防止外部使用此类
private Object data;//表示保存的数据
private Node next;//保存下一个节点
public Node(Object data){//有数据才可以保存节点
this.data=data;
}
}
//*******************************************
private Node root;//根节点
}
在随后完善的代码过程之中,除了功能的实现之外,实际上也属于接口功能的完善。
2.2 完整链表实现
interface Link{
public void add(Object data);//数据增加
public int size();//获得链表大小
public boolean isEmpty();//判断是否为空集合
public boolean contains(Object data);//判断是否存在指定元素
public Object get(int index);//根据索引取得数据
public void set(int index,Object obj);//修改数据
public void remove(Object data);//数据删除
public void clear();//清空链表
public Object[] toArray();//对象数组转换
}
class LinkImpl implements Link{
private class Node{//使用私有内部类,防止外部使用此类
private Object data;//表示保存的数据
private Node next;//保存下一个节点
public Node(Object data){//有数据才可以保存节点
this.data=data;
}
//第一次调用:this=LinkImpl.root
//第二次调用:this=LinkImpl.root.next
//第三次调用:this=LinkImpl.root.next.next
public void addNode(Node newNode){
if(this.next==null){//当前节点后没有节点
this.next=newNode;
}else{//当前节点后有节点
this.next.addNode(newNode);
}
}
public boolean containsNode(Object data){
if(this.data.equals(data)){//该节点数据束符合于查找数据
return true;
}else {//继续向下查找
if(this.next!=null){//当前节点还有下一个节点
return this.next.containsNode(data);
}else {
return false;
}
}
}
public Object getNode(int index){//传递索引序号
if(LinkImpl.this.foot++==index){//当前的索引为要查找的索引
return this.data;//返回节点对象
}else {
return this.next.getNode(index);
}
}
public void setNode(int index,Object data){
if(LinkImpl.this.foot++==index){//当前的索引为要查找的索引
this.data=data;//重新保存数据
}else {
this.next.setNode(index, data);
}
}
public void removeNode(Node pre,Object data){
if(this.data.equals(data)){//为当前要删除的数据
pre.next=this.next;
}else {
pre.next.removeNode(this, data);
}
}
public void toArrayNode(){
LinkImpl.this.retData[LinkImpl.this.foot++]=this.data;
if(this.next!=null){
this.next.toArrayNode();
}
}
}
//*******************************************
private Node root;//根节点
private int count=0;//纪律链表大小
private int foot=0;//操作的索引脚标
private Object retData[]=null;
public void add(Object data){
if(data==null){//没有增加的数据
return ;//结束调用
}
Node newNode = new Node(data);//将数据包装为Node对象,这样才可以进行先后关系排列
//没有根节点时
if(this.root==null){
this.root=newNode;//第一个节点作为根节点
}else{//根节点存在,交由Node处理
this.root.addNode(newNode);
}
this.count++;//添加成功 ,链表长度+1
}
public int size(){//获得链表大小
return this.count;
}
public boolean isEmpty(){
return this.root==null;
}
public boolean contains(Object data) {
if(this.root==null){
return false;
}
return this.root.containsNode(data);
}
public Object get(int index) {
if(index>=this.count){//索引不存在
return null;
}
this.foot=0;//查询之前进行初始化
return this.root.getNode(index);
}
public void set(int index, Object obj) {
if(index>=this.count){//索引不存在
return ;
}
this.foot=0;//查询之前进行初始化
this.root.setNode(index, obj);
}
public void remove(Object data) {
if(this.contains(data)){//数据如果存在即删除
if(this.root.data.equals(data)){//跟元素为要删除的元素
this.root=this.root.next;
}else {//不是根元素
this.root.next.removeNode(this.root, data);
}
}
count--;
}
public void clear() {
this.root=null;
this.count=0;
System.gc();//内存清空
}
public Object[] toArray() {
if(this.root==null){
return null;
}
this.retData=new Object[this.count];
this.foot=0;
this.root.toArrayNode();
return this.retData;
}
}
以上的设计都没有考虑过性能问题,只是简单的单向链表,重点是方法的理解与实现