【数据结构】java实现单链表

链表是一种常见的数据结构,由一系列节点组成。每个节点包含一个数据元素和一个指向下一个节点的指针。节点通过指针连接在一起,形成一个链式结构。
在这里插入图片描述
链表适合在需要频繁插入和删除节点的场景中使用,因为链表的插入和删除操作只需要修改相邻节点的指针,而不需要移动其他节点。相比之下,数组在插入和删除操作时需要移动其他元素,效率较低。

在Java中要实现链表,可以定义一个节点类,包含一个数据域和一个指针域。然后定义一个链表类,包含一个头节点指针和一些基本操作。

我们首先要定义出一个节点类

/**
 * @Description: 单链表节点类
 */
public class Node<E> {
	// 数据
    E data;
    // 指针
    Node next;

    public Node() {
    }

    public Node(E data) {
        this.data = data;
    }
}

然后定义一个单链表类
【为了方便操作我们设置了首尾节点,当然也可以不用尾节点,遍历一遍链表就找到尾节点了】

/**
 * @Description: 单链表类
 */
public class LinkList<E> {
    //    头结点
    private Node head;
    //    尾节点
    private Node last;
    //    链表的实际长度
    private int size;

    public LinkList() {
        head = new Node();
        last = head;
    }

    public Node getHead() {
        return head;
    }

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

    //    打印单链表
    public void display(Node head) {
        Node temp = head.next;
        while (temp.next != null) {
            System.out.print(temp.data + "-->");
            temp = temp.next;
        }
        System.out.println(temp.data);
    }

接下来我们就可以用单链表来实现一些基本操作了

  • 创建单链表(头插法、尾插法)
// 传入一个数组作为链表的内容 当然也可以只传入一个data数据,那直接插入就可以,不用for循环了
public void creatLinkList(E[] arr) {
//        头插法
    Node p;
    /*for(E i:arr){
        p = new Node(i);
        p.next = head.next;
        head.next = p;
        size++;
    }*/
//        尾插法
    for (E i : arr) {
        p = new Node(i);
        last.next = p;
        last = p;
        size++;
    }
}
  • 在指定位置插入节点
public void insertElement(int index, E data) throws Exception {
    if (index > size + 1 || index < 0) {
        throw new Exception("请选择合适的位置插入!");
    }
    Node p = new Node(data);
    Node temp = head;
    if (this.isEmpty()) {
        head.next = p;
        size++;
        last = p;
        return;
    } else if (index == size + 1) {
        last.next = p;
        last = p;
        size++;
        return;
    }
    for (int i = 1; i < index && temp.next != null; i++) {
        temp = temp.next;
    }
    p.next = temp.next;
    temp.next = p;
    
    size++;
}
  • 修改指定位置节点
public void changeElement(int index, E data) throws Exception {
    if (index > size || index <= 0) {
        throw new Exception("请选择合适的位置修改!");
    }
    Node temp = head;
    for (int i = 1; i <= index && temp != null; i++) {
        temp = temp.next;
    }
    temp.data = data;
}
  • 删除指定位置节点
public void removeElement(int index) throws Exception {
    if (index > size || index <= 0) {
        throw new Exception("请选择合适的位置删除!");
    }
    Node temp = head;
    for (int i = 1; i < index && temp != null; i++) {
        temp = temp.next;
    }
    if (index == size) {
        temp.next = null;
        last = temp;
    } else {
        temp.next = temp.next.next;
    }
}
  • 根据索引找元素
public Object getElementByIndex(int index) throws Exception {
    if (index > size || index <= 0) {
        throw new Exception("超出范围!");
    }
    Node temp = head;
    for (int i = 1; i <= index && temp != null; i++) {
        temp = temp.next;
    }
    System.out.println(temp.data);
    return temp.data;
}
  • 根据元素找索引
public int getIndexByElement(E data) {
    Node temp = head;
    for (int i = 0; i <= size && temp != null; i++) {
        if (data.equals(temp.data) || data == temp.data) {
            System.out.println(i);
            return i;
        }
        temp = temp.next;
    }
    if (!data.equals(temp.data) || data != temp.data) {
        System.out.println("该链表不存在该元素");
    }
    return -1;
}
  • 删除重复节点
/**
我们可以利用集合不能存放重复元素的特点,往一个集合中添加元素如果添加成功就留着,如果添加失败说明是重复元素
*/
public void deleteIdenticalElement() {
//        判断是否需要删除
    if (size < 2) {
        System.out.println("该链表不用进行删除重复元素操作!");
        return;
    }
    HashSet<E> set = new HashSet<>();
    Node temp = head.next;
    Node h1 = head;
    while (temp != null) {
        if (set.contains(temp.data)) {
            h1.next = temp.next;
            size--;
        } else{
            set.add((E) temp.data);
            h1 = temp;
        }
        temp = temp.next;
    }
}
  • 将单链表置逆
//    将单链表就地置逆
public void ReverseOrder() {
    Node temp = head;
    Node temp1 = temp.next;
    Node n;
    while (temp1 != null) {
        n = temp1;
        temp1 = temp1.next;
        if (temp == head) {
//                把第一个节点断开
            n.next = null;
        } else {
//                用头插法置逆
            n.next = temp;
        }
        temp = n;
    }
    head.next = temp;
}

//    将单链表置逆算法二
public void ReverseOrder2() {
    Node prev = null;
    Node current = head.next;
    while (current != null) {
        Node next = current.next;
        current.next = prev;
        prev = current;
        current = next;
    }
    head.next = prev;
}
  • 在一个递增有序列表中,插入一个值使其依旧保持有序
public void insertKeepOrderly(E data) {
    Node p = new Node(data);
    if (size == 0) {
        head.next = p;
        size++;
        return;
    }
    Node temp = head;
    while (temp.next != null) {
        if ((Integer) temp.next.data < (Integer) data) {
            temp = temp.next;
        } else {
            p.next = temp.next;
            temp.next = p;
            return;
        }
    }
    temp.next = p;
}
  • 合并两个递增有序单链表A,B到有序单链表C
public Node mergeLinkList(LinkList<Integer> list1, LinkList<Integer> list2) {
    Node h1 = list1.getHead().next;
    Node h2 = list2.getHead().next;
    if (h1 == null) {
        return h2;
    }
    if (h2 == null) {
        return h1;
    }
    Node h = new Node();
    Node last = h;
    while (h1 != null && h2 != null) {
        if ((int) h1.data <= (int) h2.data) {
            last.next = h1;
            last = h1;
            h1 = h1.next;
        } else {
            last.next = h2;
            last = h2;
            h2 = h2.next;
        }
    }
    if (h1 != null) {
        last.next = h1;
    }
    if (h2 != null) {
        last.next = h2;
    }
    return h;
}

最后附上完整的代码

/**
 * @Description: 单链表类
 */
public class LinkList<E> {
    //    头结点
    private Node head;
    //    尾节点
    private Node last;
    //    链表的实际长度
    private int size;

    public LinkList() {
        head = new Node();
        last = head;
    }

    public Node getHead() {
        return head;
    }

    public Node getLast() {
        Node temp = head.next;
        while (temp != null) {
            temp = temp.next;
        }
        return temp;
    }

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


    //    打印单链表
    public void display(Node head) {
        Node temp = head.next;
        while (temp.next != null) {
            System.out.print(temp.data + "-->");
            temp = temp.next;
        }
        System.out.println(temp.data);
    }

    //    头插法,尾插法
    public void creatLinkList(E[] arr) {
        //        头插法
        Node p;
        /*for(E i:arr){
            p = new Node(i);
            p.next = head.next;
            head.next = p;
            size++;
        }*/
        //        尾插法
        for (E i : arr) {
            p = new Node(i);
            last.next = p;
            last = p;
            size++;
        }
    }

    //    指定位置插入元素
    public void insertElement(int index, E data) throws Exception {
        if (index > size + 1 || index <= 0) {
            throw new Exception("超出范围!");
        }
        Node p = new Node(data);
        Node temp = head;
        if (this.isEmpty()) {
            head.next = p;
            size++;
            last = p;
            return;
        } else if (index == size + 1) {
            last.next = p;
            last = p;
            size++;
            return;
        }
        for (int i = 1; i < index && temp.next != null; i++) {
            temp = temp.next;
        }
        p.next = temp.next;
        temp.next = p;
        size++;
    }

    //    修改指定位置元素
    public void changeElement(int index, E data) throws Exception {
        if (index > size || index <= 0) {
            throw new Exception("超出范围!");
        }
        Node temp = head;
        for (int i = 1; i <= index && temp != null; i++) {
            temp = temp.next;
        }
        temp.data = data;
    }

    //    删除指定位置元素
    public void removeElement(int index) throws Exception {
        if (index > size || index <= 0) {
            throw new Exception("超出范围!");
        }
        Node temp = head;
        for (int i = 1; i < index && temp != null; i++) {
            temp = temp.next;
        }
        if (index == size) {
            temp.next = null;
            last = temp;
        } else {
            temp.next = temp.next.next;
        }
    }

    //    查找第i个元素
    public Object getElementByIndex(int index) throws Exception {
        if (index > size || index <= 0) {
            throw new Exception("超出范围!");
        }
        Node temp = head;
        for (int i = 1; i <= index && temp != null; i++) {
            temp = temp.next;
        }
        System.out.println(temp.data);
        return temp.data;
    }

    //    查找元素i的索引
    public int getIndexByElement(E data) {
        Node temp = head;
        for (int i = 0; i <= size && temp != null; i++) {
            if (data.equals(temp.data) || data == temp.data) {
                System.out.println(i);
                return i;
            }
            temp = temp.next;
        }
        if (!data.equals(temp.data) || data != temp.data) {
            System.out.println("该链表不存在该元素");
        }
        return -1;
    }

    //    删除重复元素
    /*public void deleteIdenticalElement() throws Exception {
//        判断是否需要删除
        if (size < 2) {
            System.out.println("该链表不用进行删除重复元素操作!");
            return;
        }
//        第一层遍历用来获取待判断的节点
//        第二层循环用来查找是否有相同元素,有的话直接删除
        Node p1 = head.next;
        Node p2;
        int l = 0;  //用来记录删除了几个元素
        int t;      //用来记录第二层遍历下标
        while (p1 != null) {
            p2 = p1.next;
            t = 2;
            while (p2 != null) {
                if (p2.data.equals(p1.data)) {
                    this.removeElement(t - l);
                    l++;
                }
                t++;
                p2 = p2.next;
            }
            l = 0;
            t++;
            p1 = p1.next;
        }
    }*/

    public void deleteIdenticalElement() {
    //        判断是否需要删除
        if (size < 2) {
            System.out.println("该链表不用进行删除重复元素操作!");
            return;
        }
        HashSet<E> set = new HashSet<>();
        Node temp = head.next;
        Node h1 = head;
        while (temp != null) {
            if (set.contains(temp.data)) {
                h1.next = temp.next;
                size--;
            } else{
                set.add((E) temp.data);
                h1 = temp;
            }
            temp = temp.next;
        }
        temp  = head.next;
        while (temp.next != null) {
            temp = temp.next;
        }
        last = temp;
        System.out.println(last.data);
    }

    //    将单链表就地置逆
    public void ReverseOrder() {
        Node temp = head;
        Node temp1 = temp.next;
        Node n;
        while (temp1 != null) {
            n = temp1;
            temp1 = temp1.next;
            if (temp == head) {
    //                把第一个节点断开
                n.next = null;
            } else {
    //                用头插法置逆
                n.next = temp;
            }
            temp = n;
        }
        head.next = temp;
    }

    //    将单链表置逆算法二
    public void ReverseOrder2() {
        Node prev = null;
        Node current = head.next;
        while (current != null) {
            Node next = current.next;
            current.next = prev;
            prev = current;
            current = next;
        }
        head.next = prev;
    }

    //    在一个递增有序列表中,插入一个值使其依旧保持有序
    public void insertKeepOrderly(E data) {
        Node p = new Node(data);
        if (size == 0) {
            head.next = p;
            size++;
            return;
        }
        Node temp = head;
        while (temp.next != null) {
            if ((Integer) temp.next.data < (Integer) data) {
                temp = temp.next;
            } else {
                p.next = temp.next;
                temp.next = p;
                return;
            }
        }
        temp.next = p;
    }

    //    合并两个递增有序单链表A,B到有序单链表C
    public Node mergeLinkList(LinkList<Integer> list1, LinkList<Integer> list2) {
        Node h1 = list1.getHead().next;
        Node h2 = list2.getHead().next;
        if (h1 == null) {
            return h2;
        }
        if (h2 == null) {
            return h1;
        }
        Node h = new Node();
        Node last = h;
        while (h1 != null && h2 != null) {
            if ((int) h1.data <= (int) h2.data) {
                last.next = h1;
                last = h1;
                h1 = h1.next;
            } else {
                last.next = h2;
                last = h2;
                h2 = h2.next;
            }
        }
        if (h1 != null) {
            last.next = h1;
        }
        if (h2 != null) {
            last.next = h2;
        }
        return h;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值