链表的基本介绍
如果现在要保存多个对象,那么首先可以想到的就是对象数组;如果我们想要保存多个任意对象,那么可以想到的一定是Object型的数组。
Object[] data=new Object[4];
但是数组最大的缺点就是长度固定,在实际开发中我们并不知道自己到底要用多少个对象,所以如果我们使用对像数组申请的空间多或者少都有可能造成空间浪费。这个时候,我们就想定义一个动态申请空间有多少数据就存多少数据的结构——链表。
范例:Java链表结点结构
class Node{
private Object data;//保存节点中的数据
private Node next;//引用,指向下一个结点
//构造函数
public Node(Object data){
this.data=data;
}
//得到对象数据
public Object getData(){
return this.data;
}
//得到对象的下一个结点
public Node getNext(){
return this.next;
}
//设置对象的下一个结点
public void setNext(Node next){
this.next=next;
}
//设置对象的数据
public void setData(Object data){
this.data=data;
}
}
public class Test {
public static void main(String[] args){
//封装结点
Node head=new Node("头结点");
Node first=new Node("结点1");
Node second=new Node("结点2");
Node last=new Node("尾结点");
//结点挂载
head.setNext(first);
first.setNext(second);
second.setNext(last);
//打印结点
print(head);
}
public static void print(Node node){
Node cur=node;
while(cur!=null){
System.out.println(node.getData());
node=node.getNext();
}
}
}
观察上面链表的实现,Node类的核心作用在于保存数据和连接结点关系。但是发现我们得自己手动对结点进行创建和挂载。这个时候我们就想能不能创建一个Link类来实现结点之间的动态挂载,而我们只需要把数据传进去就好了?
双向链表的实现
interface ILink {
/**
* 链表增加节点操作
* @param data 节点内容
* @return
*/
boolean add(Object data);
/**
* 判断指定内容节点在链表中是否存在
* @param data 要判断的内容
* @return 返回找到的节点索引
*/
int contains(Object data);
/**
* 删除指定内容节点
* @param data
* @return
*/
boolean remove(Object data);
/**
* 根据指定下标修改节点内容
* @param index 索引下标
* @param newData 替换后的内容
* @return 替换之前的节点内容
*/
Object set(int index,Object newData);
/**
* 根据指定下标返回节点内容
* @param index
* @return
*/
Object get(int index);
/**
* 链表清空
*/
void clear();
/**
* 将链表转为数组
* @return 返回所有节点内容
*/
Object[] toArray();
/**
* 链表长度
* @return
*/
int size();
/**
* 遍历链表
*/
void printLink();
}
class LinkImpl implements ILink{
private Node first;
private Node last;
private int size = 0;
private class Node{
private Node prev;
private Object data;
private Node next;
public Node(Node prev,Object data,Node next){
this.prev = prev;
this.data = data;
this.next = next;
}
}
public boolean add(Object data) {
Node newNode = new Node(this.last,data,null);
if(this.first == null){
this.first = newNode;
}
else{
this.last.next = newNode;
}
this.last = newNode;
this.size++;
return true;
}
@Override
public int contains(Object data) {
int index = 0;
if(data == null){
for(Node temp=first; temp!=null; temp=temp.next){
if(temp.data == null){
return index;
}
index++;
}
return -1;
}
for(Node temp=first; temp!=null; temp=temp.next) {
if(data.equals(temp.data)){
return index;
}
index++;
}
return -1;
}
@Override
public boolean remove(Object data) {
if(data == null){
for(Node temp=first; temp!=null; temp=temp.next){
if(temp.data == null){
unLink(temp);
return true;
}
}
return false;
}
for(Node temp=first; temp!=null; temp=temp.next){
if(data.equals((temp.data))){
unLink(temp);
return true;
}
}
return false;
}
@Override
public Object set(int index, Object newData) {
if(!isLinkIndex(index)){
return false;
}
Node node = node(index);
Object element = node.data;
node.data = newData;
return element;
}
@Override
public Object get(int index) {
if(isLinkIndex(index)){
return node(index).data;
}
return null;
}
@Override
public void clear() {
for(Node temp=first; temp!=null;){
temp.data = null;
Node node = temp.next;
temp.prev = temp.next = null;
temp = node;
this.size--;
}
}
@Override
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for(Node temp=first; temp!=null; temp=temp.next){
result[i++] = temp.data;
}
return result;
}
@Override
public int size() {
return this.size;
}
@Override
public void printLink() {
Object[] data = this.toArray(); //字符串变成字符串数组
for(Object temp:data){
System.out.println(temp);
}
}
/**
* 根据指定索引取得具体节点
* @param index
* @return
*/
private Node node(int index) {
//从前往后找快
if(index<(size>>1)){
Node temp = first;
//走index步
for(int i=0; i<index; i++){
temp = temp.next;
}
return temp;
}
//否则从后往前找快
Node temp = last;
//走index步
for(int i=size-1; i>index; i--){
temp = temp.prev;
}
return temp;
}
/**
* 判断指定索引是否合法
*/
private boolean isLinkIndex(int index){
return (index>=0) && (index<size);
}
//删除指定的结点
private Object unLink(Node node){
Object elementData = node.data;
Node prev = node.prev;
Node next = node.next;
if(prev != null){
//该节点不是头节点
prev.next = next;
node.prev = null;
}
else{//是头节点
this.first = next;
}
if(next != null){
//不是尾节点
next.prev = prev;
node.next = null;
}
else{
//是尾节点
this.last = prev;
}
this.size--;
return elementData;
}
}
public class Test {
public static void main(String[] args) {
ILink link = new LinkImpl();
link.add(1);
link.add(2);
link.add(3);
link.printLink();
link.remove(1);
link.printLink();
}
}

本文介绍了链表作为数组替代品的原因,强调了其动态分配空间的优势。文章详细讲解了Java中链表节点的结构,并探讨了如何简化节点创建与连接,特别是对于双向链表的实现进行了讨论。
1862

被折叠的 条评论
为什么被折叠?



