本文将数据结构知识中重要知识点:数据元素,结点,数据类型,抽象数据类型,抽象数据类型的实现、以及对新定义的数据结构的应用等知识通过下述java代码的形式串联起来,以从宏观上对数据结构有一个透彻的理解和认识。
我们要使用单链表这个数据结构来解决问题的前提是首先得创建一个单链表数据结构。创建单链表数据结构,就得自定义个单链表的抽象数据类型,抽象数据类型只是对数据结构定义一组逻辑操作,没有具体的实现。在实际应用中,必须实现这个抽象数据类型,才能使用它们,而实现抽象数据类型依赖于数据存储结构。
单链表
线性表的链式存储是用若干地址分散的存储单元存储数据元素,逻辑上相邻的数据元素在物理位置上不一定相邻,必须采用附加信息表示数据元素之间的顺序关系。因此,存储一个数据元素的存储单元至少包含两部分——数据域和地址域,结构如下:
其中data存储数据元素值,称为数据域;next存储后继元素的地址,称为地址域或链(link),上述结构通常称为结点(node)。一个结点表示一个数据元素。
根据上一博客日记中的ListInterface接口,实现单链表类LList,节点类Node在LList类中,代码如下:
public class LList<T> implements ListInterface<T> {
private Node firstNode;
private int length;
public LList(){
clear();
}
public final void clear(){
firstNode = null;
length = 0;
}
public boolean add(T newEntry){
Node newNode = new Node(newEntry);
if(isEmpty())
firstNode = newNode;
else{//插入到非空线性表的末尾
Node lastNode = getNodeAt(length);
lastNode.next = newNode;//使最后一个结点的引用指向新结点
}
length++;
return true;
}
public boolean add(int newPosition,T newEntry){
boolean isSuccessful = true;
if((newPosition >=1)&&(newPosition <= length + 1)){
Node newNode = new Node(newEntry);
if(isEmpty()||(newPosition ==1)){//线性表为空
newNode.next = firstNode;
firstNode = newNode;
}else {//线性表不为空 newPosition>1
Node nodeBefore = getNodeAt(newPosition - 1);
Node nodeAfter = nodeBefore.next;
newNode.next = nodeAfter;
nodeBefore.next = newNode;
}
length++;
}else {
isSuccessful = false;
}
return isSuccessful;
}
public int getLength(){
return length;
}
private Node getNodeAt(int givenPosition){
Node currentNode = firstNode;
if((currentNode.next != null)||!isEmpty()){
for (int counter = 1;counter < givenPosition;counter++){
currentNode = currentNode.next;
}
}
return currentNode;
}
public boolean replace(int givenPosition,T newEntry){
boolean isSuccessful = true;
if(!isEmpty()&&(givenPosition >= 1)&&(givenPosition <= length)){
Node desiredNode = getNodeAt(givenPosition);
desiredNode.data = newEntry;
}else
isSuccessful = false;
return isSuccessful;
}
public T getEntry(int givenPosition){
T result = null;
if(!isEmpty()&&(givenPosition >= 1)&&(givenPosition <= length)){
result = getNodeAt(givenPosition).data;
}
return result;
}
public Object remove(int givenPosition){
Object result = null;
if(!isEmpty()&&(givenPosition >= 1)&&(givenPosition <= length)){
if(givenPosition == 1){
//删除第一个元素
result = firstNode.data;
firstNode = firstNode.next;
}else {
//givenPosition > 1删除中间或末尾的元素
Node nodeBefore = getNodeAt(givenPosition -1);
Node nodeToRemove = nodeBefore.next;
Node nodeAfter = nodeToRemove.next;
nodeBefore.next = nodeAfter;
result = nodeToRemove.data;
}
length--;
}
return result;
}
public void display(){
Node currentNode = firstNode;
while(currentNode != null){
System.out.println(currentNode.data);
currentNode = currentNode.next;
}
}
public boolean contains(T anEntry){
boolean found = false;
Node currentNode = firstNode;
while(!found && (currentNode != null)){
if(anEntry.equals(currentNode.data)){
found = true;
}else
currentNode = currentNode.next;
}
return found;
}
public boolean isFull(){return false;}
public boolean isEmpty(){return length == 0;} //判断线性表是否为空。
private class Node {
private T data;
private Node next;
private Node(T dataPortion){
data = dataPortion;
next = null;
}
private Node(T dataPortion,Node nextNode){
data = dataPortion;
next = nextNode;
}
}
}
链表实现线性表的优缺点:
1.可根据需要延长线性表;
2.在插入与删除结点时不需要移动线性表中已存在的任何一个元素。但是,在使用链表时,必须从链表的始端起遍历链表,以确定应该在何处插入或删除
3.从链表中检索一个已有的元素,需要类似的遍历以查找想得到的元素。
4.链表比数组需要更多的内存。