数据结构-Java实现链表

概念

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间。

本文讲述使用Java实现单向链表、以及如何使用数据来实现单向链表

单向链表的Java实现

链表节点结构

package com.billJiang.stack;

/**
 * Created by billJiang on 2016/11/30.
 * 单向链表节点
 */
public class Node<T> {
    private T item;

    private Node<T> next;

    public Node() {
        this.item = null;
        this.next = null;
    }

    public Node(T item, Node<T> next) {
        this.item = item;
        this.next = next;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }

    public Node<T> getNext() {
        return next;
    }

    public void setNext(Node<T> next) {
        this.next = next;
    }
}

链表实现

package com.billJiang.link;


import com.billJiang.stack.Node;

/**
 * Created by billJiang on 2016/12/2.
 * 单项链表
 */
public class Link<T> {

    private int size = 0;
    private Node<T> first;
    private Node<T> last;

    public void add(int index, T element) {
        //TODO 书本60 61页有问题
        if (index <= size && index >= 0) {
            if (index == 0) {
                addFirst(element);
            } else if (index == size) {
                addLast(element);
            } else {
                Node node = this.get(index - 1);
                Node next = node.getNext();
                Node cur = new Node(element, next);
                node.setNext(cur);
                size++;
            }
        } else {
            throw new IndexOutOfBoundsException("索引越界");
        }
    }

    //获取链表中的数据
    public Node get(int index) {
        Node node = first;
        int i = 0;
        while (node != null) {
            if (index == i) {
                return node;
            }
            i++;
            node = node.getNext();
        }
        return null;
    }

    public T getValue(int index) {
        return this.get(index) == null ? null : (T) this.get(index).getItem();
    }

    public void addFirst(T element) {
        if (size == 0)
            fillStart(element);
        else {
            Node<T> node = new Node(element, first);
            first = node;
            size++;
        }
    }

    public void addLast(T element) {
        Node<T> node = new Node(element, null);
        last.setNext(node);
        last = node;
        size++;
    }

    public boolean isEmpty() {
        return first == null && last == null;
    }

    public void fillStart(T element) {
        Node<T> node = new Node(element, null);
        first = node;
        last = first;
        size++;
    }

    public void remove(int index) {
        if (index < size && index >= 0) {
            if (index == 0) {
                removeFirst();
            } else if (index == size - 1) {
                removeLast();
            } else {
                Node temp = this.get(index);
                Node pre = this.get(index - 1);
                pre.setNext(temp.getNext());
                temp = null;
                size--;
            }
        } else {
            throw new IndexOutOfBoundsException("索引越界");
        }
    }

    public void removeFirst() {
        Node temp = first;
        first = temp.getNext();
        temp = null;
        //如果只有一个元素,则first为null,将last也置为null
        if (first == null) {
            last = null;
        }
        size--;
    }

    public void removeLast() {
        //找到倒数第二个
        Node node = this.get(size - 2);
        node.setNext(null);
        last = node;
        size--;
    }

    //链表反转
    public void reverse(){
        if(isEmpty()||size==1){
            return;
        }
        Node pre=first;
        last=pre;
        for(Node node=first.getNext();node!=null;){
            Node temp=node.getNext();
            node.setNext(pre);
            pre=node;
            node=temp;
        }
        last.setNext(null);
        first=pre;
    }

    public void printAll(){
        for(Node<T> node=first;node!=null;node=node.getNext()){
            System.out.print("-->"+node.getItem().toString());
        }
    }

}

测试

package com.billJiang.link;

/**
 * Created by billJiang on 2016/12/2.
 */
public class LinkTest {
    public static void main(String[] args) {
        Link<Integer> link=new Link<Integer>();
        link.add(0,1);
        link.add(1,2);
        link.add(2,3);
        link.add(3,4);
        link.add(4,5);
        link.printAll();
        link.remove(3);
        System.out.println();
        System.out.println("------after romeve--------");
        link.printAll();
        link.reverse();
        System.out.println();
        System.out.println("----after reverse-------");
        link.printAll();
        System.out.println();
        System.out.println("hello world");
    }
}

使用数组实现链表

节点结构定义

package com.billJiang.link;

/**
 * Created by billJiang on 2016/12/2.
 * 使用数组实现链表
 */
public class Element<T> {
    T data;
    int nextIndex;

    public Element(T data,int nextIndex) {
        this.data=data;
        this.nextIndex=nextIndex;
    }
}

具体实现

package com.billJiang.link;

/**
 * Created by billJiang on 2016/12/2.
 * 使用数据模拟链表
 */
public class LinkArray<T> {
    private Element[] items;
    private int size = 0;//元素个数
    private int unused_head = 0;

    //存储内容链表的头尾位置
    private int first;
    private int last;

    public LinkArray(int capacity) {
        items = new Element[capacity];
        for (int i = 0; i < capacity - 1; i++) {
            items[i] = new Element<>(null, i + 1);
        }
        items[capacity - 1] = new Element<>(null, -1);
    }

    public void add(int index, T data) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("索引越界");
        }
        if (checkFull()) {
            return;//满了
        }
        if (index == 0) {
            addFirst(data);
        } else if (index == size) {
            addLast(data);
        } else {
            //获取要插入位置的前一个元素
            Element e = this.get(index - 1);
            items[unused_head].data = data;
            int unused = items[unused_head].nextIndex;
            items[unused_head].nextIndex = e.nextIndex;
            e.nextIndex = unused_head;
            unused_head = unused;
            size++;
        }
    }

    public void addFirst(T data) {
        if (this.isEmpty()) {
            fillStart(data);
            size++;
        } else {
            //空链表的下一个索引下标
            int index = items[unused_head].nextIndex;
            items[unused_head].data = data;
            items[unused_head].nextIndex = first;
            first = unused_head;
            unused_head = index;
            size++;
        }
    }


    public void addLast(T data) {
        int index = items[unused_head].nextIndex;
        items[unused_head].data = data;
        items[unused_head].nextIndex = -1;
        items[last].nextIndex = unused_head;
        last = unused_head;
        unused_head = index;
        size++;
    }

    public void remove(int index) {
        if (index < 0 || index > size - 1) {
            throw new IndexOutOfBoundsException("索引越界");
        }
        if (index == 0) {
            removeFirst();
        } else {
            if (isEmpty())
                return;
            Element pre = get(index - 1);
            int del = pre.nextIndex;
            Element delElement = items[del];
            pre.nextIndex = delElement.nextIndex;
            if (index == size - 1) {
                if (index >= 2)
                    last = get(index - 2).nextIndex;
                else if (index == 1) {
                    last = first;
                }
            }
            delElement.nextIndex = unused_head;
            unused_head = del;
            size--;
        }

    }

    public void removeFirst() {
        Element e = items[first];
        if (size == 1) {
            last = first;
        }
        items[first].data = null;
        items[first].nextIndex = unused_head;
        unused_head=first;
        first = e.nextIndex;
        size--;
    }

    public Element get(int index) {
        Element e = items[first];
        for (int i = 0; i < index; i++) {
            e = items[e.nextIndex];
        }
        return e;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void fillStart(T data) {
        Element element = items[unused_head];
        element.data = data;
        first = unused_head;
        last = unused_head;
        unused_head = element.nextIndex;
        element.nextIndex = -1;
    }

    public boolean checkFull() {
        if (size == items.length) {
            return true;
        }
        return false;
    }

}

测试

package com.billJiang.link;

/**
 * Created by billJiang on 2016/12/2.
 */
public class LinkArrayTest {
    public static void main(String[] args) {
        LinkArray<Integer> la=new LinkArray<>(3);
        la.add(0,1);
        la.add(1,2);
        la.add(0,3);
        la.remove(0);
        la.add(1,4);

    }
}

链表特点

1、物理空间不连续,空间开销大
2、在运行时可以动态添加
3、查找元素需要顺序查找
4、操作略微复杂

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值