一说得到链表,我们就会在脑中自然而然的弹出ADT这个概念,既就是所有的数据结构书上说的那样,抽象数据类型(Abstract Data Type),听起来好像很高深,其实只不过就是那些在我们前面的人根据那些东西的用法给那个起了个抽象的名字。现在我们就看看这个称为链表的东东。
链表这种数据结构呢,就像是用绳子穿起一串珠子,这个珠子就是链表中的称为“节点”的东东,而那个绳子呢,就是把这些珠子穿起来的东西,在链表中就是指向下一个节点的引用。就这样,第一个的节点里面存第二个节点的引用,第二个节点里面存第三个的,。。。。。就这样下去了,很形象的说就是这个样子。但是说简单也简单,说不简单也不简单,因为这里面不是穿珠子,我们还要会“玩珠子”,我们可以把在里面取一个珠子,用暴力的方法,把绳子拽断,取一个珠子,然后再把绳子接起来。。。。。等等还有其他操作。但是大神们请记住,我这里的珠子就是链表中的节点。。。。。。
然后呢,下面就是本菜鸟的大作了,先是使用接口规范链表中要实现的方法,包括上面说的“拽珠子”,以及还有别的方法的玩这些“珠子”。。。。。。。我还是给大家代码示例吧,说多了就成语文是体育老师教的了。。。
一:
用来规范的接口
/**
* 编写泛类型接口,来规范实现链表中方法
* @author LONG
*
*/
public interface ADT<T> {
/**
* Task:在链表中添加新的元素,默认在链表的末尾添加
* @param newEntry 用来添加的新元素
* @return 如果成功则返回true,否则返回false
*/
public boolean add(T newEntry);
/**
* Task:在链表中的指定位置添加新的元素
* @param newEntry 用来添加的新的元素
* @param position 指定添加的位置,在链表中的第position个
* @return 返回是否成功,如果成功,则返回true,否则返回false
*/
public boolean add(T newEntry,int position);
/**
* Task:删除指定位置的元素,并且返回该元素
* @param position 传入的指定位置
* @return 返回删除的元素
*/
public T remove(int position);
/**
* Task:在链表中查找给定的数据,并给用户说明给数据在链表中存储的位置,如果没有找到也告诉用户
* @param data 需要查找的元素
* @return 返回查找信息
*/
public String select(T data);
/**
* Task:将链表中对象的数据全部显示出来
*/
public void display();
/**
* Task:将链表清空
*/
public void clear();
}
二:
用来实现接口的类
/**
* 用来实现链表的接口,同样定义为泛型
* @author LONG
*
* @param <T> 用来声明该类为泛型类,由用户来定义该类存储对象类型
*/
public class TrueLink<T> implements ADT<T>{
private Node<T> head = null; //定义头节点,用来记录该链表的头部
private Node<T> end = null; //用来指向链表的尾部
private int length = 0; //用来记录链表的长度
/**
* 实现的第一个add方法,只传入节点数据
*/
public boolean add(T newEntry) {
boolean isSuccessful = true; //将初始返回值设为true
Node<T> current = new Node<T>(newEntry); //创建新的节点保存数据
if(head != null){ //用来判断头结点是否为空,如果为空创建头结点
end.setAdd(current);
end = end.getNode();
}else{
head = current;
end = head;
}
length++; //链表长度自增1
return isSuccessful;
}
/**
* 实现的第二个add方法,同时传入数据和要添加的位置position
*/
public boolean add(T newEntry, int position) {
boolean isSuccessful = true;
if(length >= position){ //用来判断链表长度与指定位置的关系,使得指定位置必须满足在链表长度之内
Node<T> temp = head; //定义临时Node类型变量,作为中间变量
for(int i = 1; i < position - 1; i++){ //循环得到要添加位置的前一个节点
temp = temp.getNode();
}
Node<T> newNode = new Node<T>(newEntry,temp.getNode()); //创建节点,将数据newEntry传进去,同时也把下一个节点的地址传进去
temp.setAdd(newNode); //将前一个的元素的地址变量指向新的元素
length++; //链表长度自增1
}else{
isSuccessful = false;
}
return isSuccessful;
}
public T remove(int position) { //移除指定位置的元素
if(position <= length){ //首先判断指定位置是否符合链表的现有长度
Node<T> temp = head; //定义临时Node类型变量,作为中间变量
for(int i = 1; i < position - 1; i++){ //使用循环找到要删除位置的前一个元素
temp = temp.getNode();
}
Node<T> current = temp.getNode().getNode(); //将要删除处后面元素的地址保存起来
T values = (T) temp.getNode().getData(); //将要删除处的元素的数据保存起来,用来返回
temp.setAdd(current); //将要删除处的前一个元素的地址变量直接指向刚才保存起来的地址
length--; //链表长度减少一个
return values; //返回要删除处的元素的数据
}else{
return null;
}
}
public void display() {
if(head != null){ //判断链表非空
Node<T> temp = head; //定义临时Node类型的变量,作为中间变量
for(int i = 0; i < length; i++){ //使用循环将链表遍历,将元素的值打印出来
System.out.println("链表中的数据如下"+temp.getData());
temp = temp.getNode();
}
}else{
System.out.println("链表并未创建");
}
}
/**
* 实现查找功能
*/
public String select(T data) {
Node<T> temp = head; //声明了一个临时的Node类型的变量,作为中间变量
String message = null; //定义要返回的字符串
for(int i = 0; i < length - 1; i++){ //通过循环遍历整个链表,一旦找到则会退出循环
if(data.equals(temp.getData())){ //判断元素的值是否相同
message = "找到了查找数据"+data+",该数据位于链表中的第"+(i + 1)+"位";
break;
}
temp = temp.getNode();
}
return message;
}
/**
* 用来将链表清空
*/
public void clear() {
length = 0;
head = null;
end = null;
}
}
三:
定义的节点类,。。。。传说中的“珠子”
/**
* Task:用来返回该节点中封装的地址
* @return 返回下一个节点的地址
*/
public Node<T> getNode(){
return address;
}
/**
* Task:用来改变节点的数据
* @param data 传进去的数据
* @return 返回成功true
*/
public boolean setData(T data){
this.data = data;
return true;
}
/**
* Task:用来设置节点的指向地址
* @param address 传入新的地址
* @return 返回成功true
*/
public boolean setAdd(Node<T> address){
this.address = address;
return true;
}
}
至此,链表中基本会用到的,老衲已经阐述得差不多了。。。。。。各位施主大牛求评论呀!!!!!
吾不能默默无闻呀。。。。。。哈哈