数据结构之链表实现

分析:

  1. 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
  2. 单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,一个是数据域,一个是节点域。
  3. 双向链表可以从两个方向遍历

1. 单向链表

1)定义一个节点

class Node<E> {

    E e;
    Node<E> next;
    public Node(E e,Node<E> next){
        this.e = e;
        this.next = next;
    }

    public Node(E e){
        this(e,null);
    }
}

2)构造函数

//虚拟头节点
private Node<E> dummyHead;
private int size;
public LinkedList(){
    dummyHead = new Node<>(null,null);
    size = 0;
}

3)添加元素

//1->2->3->4
//1. 首先找到要插入位置的前节点
//2. 比如你要在index=2位置插入66,你就把要插入的66节点的next指向3,2的next节点指向66,然后就插入进去了
public void add(int index, E e){

    Node<E> pre = dummyHead;
    for (int i = 0; i < index; i++)
        pre = pre.next;
    Node<E> node = new Node<>(e);
    //当前待插入节点的next用待插入节点的前一个节点的next指向
    node.next = pre.next;
    //前一个节点的next指向当前节点就对了
    pre.next = node;
    size++;
}

public void addFirst(E e){
    add(0,e);
}

public void addLast(E e){
    add(size,e);
}

3)获取数据

获取数据就是获取某一个位置的节点,然后就能获取这个节点的数据了
public E get(int index){
    if(index < 0 || index > size){
        throw new IllegalArgumentException("角标不合法");
    }
    Node<E> current = dummyHead.next;
    for (int i = 0; i < index; i++) {
        current = current.next;
    }
    return current.e;
}

public E getFirst(){
    return get(0);
}

public E getLast(){
    return get(size - 1);
}

4)修改数据

//首先找到要修改的index节点,然后直接修改
public void set(int index, E e){
    if(index < 0 || index > size){
        throw new IllegalArgumentException("角标不合法");
    }
    Node<E> current = dummyHead.next;
    for (int i = 0; i < index; i++) {
        current = current.next;
    }
    current.e = e;
}

5) 删除数据

//1->2->3->4
//假设我要删除2这个节点 我就应该找到它的前一个节点1,然后
//用1这个节点指向要删除节点的下一个节点,即3,删除节点的next=null
public E remove(int index){
    Node<E> pre = dummyHead;
    for (int i = 0; i < index; i++) {
        pre = pre.next;
    }
    if(pre == null)
        return null;
    Node<E> delNode = pre.next;
    pre.next = delNode.next;
    delNode.next = null;
    return delNode.e;
}

public E removeFirst(){
    return remove(0);
}

public E removeLast(){
    return remove(size - 1);
}

5)toString方法

@Override
public String toString(){

    StringBuilder sb = new StringBuilder();
    sb.append("LinkedList[ ");
    Node<E> current = dummyHead.next;
    //sb.append("NULL -> ");
    while (current !=  null){
        sb.append(current.e+" -> ");
        current = current.next;
    }
    sb.append("NULL]");
    return sb.toString();
}

2. 双向链表

1)头部插入数据

//添加一个对前一个节点的引用
public Node previous;

 /**
   * 插入一个结点,在头结点后进行插入
   */
  public void insertFirst(long value){
      Node node = new Node(value);
      if(first == null){
          last = node;
      }else{
          first.previous = node;
      }
      node.next = first;
      first = node;
  }

2)尾部插入数据

  /**
   * 插入一个结点,从尾结点进行插入
   */
  public void insertLast(long value){
      Node node = new Node(value);
      if (first == null){
          first = node;
      }else{
          last.next = node;
          node.previous = last;
      }
      last = node;
  }

3)头部删除数据

 /**
   * 删除一个结点,在头结点后进行删除
   */
  public Node deleteFirst(){
     if(first == null). return;
      Node current = first;
      if(first.next == null){
          last = null;
      }else{
          first.next.previous = null;
      }
      first = first.next;
      return current;
  }

4)尾部删除数据

  /**
   * 删除尾节点 从尾部进行删除
   */
  public Node deleteLast(){
      Node current = last;
      if(first.next == null){
          first = null;
      }else{
          last.previous.next = null;
      }
      //后一个节点用后一个节点的前一个节点替换
      last = last.previous;
      return last;
  }

5)删除节点数据

 /**
  * 根据数据删除节点
  * @param value
  * @return
  */
 public Node delete(long value){

     Node current = first;
     if(current == null){
         return null;
     }
     while (current.data != value){
         current = current.next;
         if(current == null){
             return null;
         }
     }
     if(current == first){
         first = first.next;
     }else{
         //当前节点的前一个节点的下一个节点就是保留当前节点的引用
         current.previous.next = current.next;
     }
     return current;
 }

3. 用链表实现栈

基于1实现的单链表LinkedList
public class LinkedListStack<E> implements Stack<E>{

    private LinkedList<E> linkedList;
    public LinkedListStack(){
        linkedList = new LinkedList<>();
    }

    //入栈
    @Override
    public void push(E e) {
        linkedList.addFirst(e);
    }

    //出栈
    @Override
    public E pop() {
        return linkedList.removeFirst();
    }

    //获取栈顶元素
    @Override
    public E peek() {
        return linkedList.getFirst();
    }

    @Override
    public boolean isEmpty() {
        return linkedList.isEmpty();
    }

    @Override
    public int size() {
        return linkedList.size();
    }

    @Override
    public String toString(){

        StringBuilder sb = new StringBuilder();
        sb.append("LinkedList[ ");
        Node<E> current = linkedList.getNode();
        while (current !=  null){
            sb.append(current.e+" -> ");
            current = current.next;
        }
        sb.append("NULL ]");
        return sb.toString();
    }
}

4. 用链表实现队列

1)构造函数

//队头 队尾
private Node<E> front;
private Node<E> tail;
private int size;
public LinkedListQueue(){
    front = null;
    tail = null;
    size = 0;
}

2)入队

@Override
public void enqueue(E e) {
    //4->3->2->1
    Node<E> node = new Node<>(e);
    if(tail == null){
        tail = node;
        front = tail;
    }else{
        tail.next = node;
        tail = tail.next;
    }
    size++;
}

3)出队

@Override
public E dequeue() {
    //4->3->2->1
    if(isEmpty())
        throw new IllegalArgumentException("队列是空的,不能出队");
    Node<E> current = front;
    front = front.next;
    current.next = null;
    if(front == null)
        tail = null;
    size--;
    return current.e;
}

4)toString方法

@Override
public String toString(){

    StringBuilder sb = new StringBuilder();
    sb.append("LinkedList size "+ size +"\n");
    Node<E> current = front;
    sb.append("front[ ");
    while (current !=  null){
        sb.append(current.e+" -> ");
        current = current.next;
    }
    sb.append("NULL ] tail");
    return sb.toString();
}

5.联系方式

QQ:1509815887
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值