06.链表

链表

  • ok,在之前我已经把顺序表的基础知识已经分享给大家了,那我们想想看,因为每个元素都有自己的索引,就和我们都有身份证号码是一样的道理,
    这就使得顺序表有着高效的查询速度,在顺序表中查询元素的时间复杂度是O(1);那我们在每一次增删操作时,紧跟其后的所有元素都得进行移动,
    有没有办法解决呢?是有的,链表。
  • 举个例子,体育课老师按照身高将学生排好一列,老师说把你前后的同学都记准确。当快要下课时老师集合同学时,他们能够快速按照原来的
    顺序排好队。我举这个栗子什么意思,别急接着往下看。

定义

  • 链表是一种物理存储单元,非连续,非顺序头结点的数据域为空,尾节点的指针域为空。元素的逻辑顺序是通过链表中的指针来链接实现,有一系列的结点(链表中的元素称为结点),
    且节点可在运行时动态生成。

单向链表

  • 由多个节点组成,每个节点都有一个数据域和一个指针域,数据域用来存储数据,指针域用来指向其后继节点,链表的头节点的数据域不存储数据,指针域
    指向第一个真正存储数据的节点。
  • 代码实现
package DataStructure.LinkedList;
public class LinkedList<T> implements Iterable<T> {
    //记录头节点
    private Node head;
    //记录链表长度
    private int N;
    //成员内部类
    public class Node {
        public T item;//存储数据
        public Node next;//指向下一个节点
        public Node(T item,Node next) {
            this.item = item;
            this.next = next;
        }
    }
    public LinkedList() {
        //初始化头节点
        this.head = new Node(null,null);
        //初始化元素个数
        this.N = 0;
    }
    public void clean() {
        head.next = null;
        N = 0;
    }
    public boolean isEmpty() {return N==0;}
    public int length() {return N;}
    //获取指定位置的元素
    public T get(int i) {
        //通过循环从头节点依次往后找i次
        Node n = head.next;//记录第一个节点
        for (int j = 0; j < i; j++) {
            n = n.next;
        }
        return n.item;
    }
    public void insert(T t) {
        //找到当前最后一个节点
        Node n = head;
        while(n.next != null) {
            n = n.next;
        }
        //创建新节点,让当前最后一个节点指向新节点
        Node node = new Node(t, null);
        n.next = node;
        //元素个数+1
        N++;
    }
    public void insert(int i,T t) {
        //1.找到i位置前一个结点
        Node n = head;
        for (int j = 0; j < i-1; j++) {
            n = n.next;
        }
        //2.找到i位置的节点
        Node current = n.next;
        //3.创建新节点,指向原来位置的节点
        Node node = new Node(t, current);
        //4.i前一个位置的节点指向新节点
        n.next = node;
        //元素个数+1
        N++;
    }
    public T remove(int i) {
        //1.找到i位置前一个结点
        Node n = head;
        for (int j = 0; j < i-1; j++) {
            n = n.next;
        }
        //2.找到i位置的节点
        Node current = n.next;
        //3.找到i位置的下一个节点
        Node nextNode = current.next;
        //4.i前一个位置的节点指向i的下一个位置节点
        n.next = nextNode;
        //元素个数-1
        N--;
        return current.item;
    }
    //第一次出现的位置
    public int indexOf(T t) {
        //从头结点遍历链表进行比较
        Node n = head;
        for (int i = 0; n.next!=null ; i++) {
            n = n.next;
            if (n.item.equals(t)) {
                return i;
            }
        }
        return -1;
    }
    //使用迭代器接口实现链表的遍历
    @Override
    public Iterator<T> iterator() {
      return new LIterator();
    }
    public class LIterator implements Iterator {
      private Node n;
      public LIterator() {
        this.n = head;
      }
    @Override
    public boolean hasNext() {
      return n.next != null;
    }
    @Override
    public Object next() {
      n = n.next;
      return n.item;
    }
  }
}

双向链表

  • 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
  • 代码实现:
package DataStructure.LinkedList.TwoWay;
import java.util.Iterator;
public class TwoWayLinkedList<T> implements Iterable<T> {
  //第一个节点
  private Node first;
  //最后一个节点
  private Node last;
  //链表的长度
  private int N;//length
  //成员内部类
  private class Node{
    //存储数据
    private T item;
    //指向上一个节点
    private Node pre;
    //指向下一个节点
    private Node next;
    public Node(T item, Node pre, Node next) {
      this.item = item;
      this.pre = pre;
      this.next = next;
    }
  }
  public TwoWayLinkedList() {
    //初始化头尾节点
    this.first = new Node(null,null,null);
    this.last = new Node(null,null,null);
    //初始化元素个数
    this.N = 0;
  }
  //1.置空
  public void clean() {
    this.first.next = null;
    this.first.pre = null;
    this.first.item = null;
    this.last = null;
    this.N = 0;
  }
  //2.判空
  public boolean isEmpty() {return N == 0;}
  //3.获取个数
  public int length() {return N;}
  //4.返回指定位置的值
  public T get(int i) {
    Node n = first.next;
    for (int j = 0; j < i; j++) {
      n = n.next;
    }
    return n.item;
  }
  //5.添加
  public void insert(T t) {
    if (isEmpty()) {
      //创建新节点
      Node node = new Node(t, first, null);
      //让新节点成为尾节点
      last = node;
      //让头结点指向尾节点
      first.next = last;
    }else {
      //不为空
      //创建新节点
      Node oldLast = last;
      Node node = new Node(t, oldLast, null);
      //当前尾节点指向新节点
      oldLast.next = node;
      //新节点成为尾节点
      last = node;
    }
    N++;
  }
  //6.i处添加
  public void insert(int i,T t) {
    if (isEmpty()) {
      return;
    }
    //找i—1处的节点
    Node pre = first;
    for (int j = 0; j < i-1; j++) {
      pre = pre.next;
    }
    //找i处的节点(当前)
    Node current = pre.next;
    //创建新节点
    Node node = new Node(t, pre, current);
    //i-1处的下一个节点变为新节点
    pre.next = node;
    //i处的上一个节点变为新节点
    current.pre = node;
    N++;
  }
  //7.删除并返回第i个元素
  public T remove(int i) {
    //找i-1处的节点
    //找i—1处的节点
    Node pre = first;
    for (int j = 0; j < i-1; j++) {
      pre = pre.next;
    }
    //找i处的节点
    Node current = pre.next;
    //找i+1处的节点
    Node nextNode = current.next;
    //让i-1的下一个节点变为i+1
    pre.next = nextNode;
    //让i+1的上一个节点变为i-1
    nextNode.pre = pre;
    N--;
    return current.item;
  }
  //8.首次出现的元素
  public int indexOf(T t) {
    Node n = first;
    for (int i = 0; n.next != null; i++) {
      n = n.next;
      if (n.next.equals(t)) {
        return i;
      }
    }
    return -1;
  }
  //9.获取第一个元素
  public T getFirst() {
    if (isEmpty()) {
      return null;
    }
    return first.next.item;
  }
  //10.获取最后一个元素
  public T getLast() {
    if (isEmpty()) {
      return null;
    }
    return last.item;
  }
  @Override
  public Iterator<T> iterator() {
    return new TIterator();
  }
  private class TIterator implements Iterator {
    private Node n;
    public TIterator() {
      this.n = first;
    }
    @Override
    public boolean hasNext() {
      return n.next != null;//true
    }
    @Override
    public Object next() {
      n = n.next;
      return n.item;
    }
  }
}
链表的复杂度分析
  • 在链表执行插入删除时,由于链表的物理地址不是连续的,即不需要预先指定存储空间大小,扩容,元素的交换等
  • 相比较顺序表,链表的查询效率明显较低,即增删快,查询慢
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值