java--无头单向非循环链表

本文详细介绍了单链表的接口定义与具体实现,包括头插法、尾插法、任意位置插入、关键字查找、删除节点等核心操作,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先创建接口

public interface ILinked {
        //头插法
        void addFirst(int data);
        //尾插法
        void addLast(int data);
        //任意位置插入,第一个数据节点为0号下标
        boolean addIndex(int index,int data);
        //关键字查找是否包含key是否在单链表当中
        boolean contains(int key);
        //删除第一次出现关键字为key的节点3.3 链表面试题
        int remove(int key);
        //删除所有值为key的节点
        void removeAllKey(int key);
        //得到单链表的长度
        int getLength();
        void display();
        void clear();
    }

然后具体实现

public class MySingleList implements ILinked {

    class Node {
        public int getData() {
            return data;
        }

        private int data;

        public Node getNext() {
            return next;
        }

        public Node next;

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

    public Node getHead() {
        return head;
    }

    private Node head;

    public MySingleList() {
        this.head = null;
    }

    @Override
    public void addFirst(int data) {
        Node node = new Node(data);
        //第一次插入的时候,没有任何的数据节点
        if (this.head == null) {
            this.head = node;
        } else {
            node.next = this.head;
            this.head = node;
        }
    }

    @Override
    public void addLast(int data) {
        Node node = new Node(data);
        if (this.head == null) {
            this.head = node;
        } else {
            Node cur = this.head;
            while (cur.next != null) {
                cur = cur.next;
            }
            //cur所指向的位置就是尾节点
            cur.next = node;
        }

    }

    //检查index合法性
    private void checkIndex(int index) {
        if (index < 0 || index > getLength()) {
            throw new UnsupportedOperationException("Index不合法");
        }
    }

    //找到index-1的位置,函数返回该位置的节点引用
    private Node searchIndex(int index) {
        int count = 0;
        Node cur = this.head;
        while (count < index - 1) {
            cur = cur.next;
            count++;
        }
        return cur;
    }

    @Override
    public boolean addIndex(int index, int data) {
        checkIndex((index));
        //头插法
        if (index == 0) {
            addFirst(data);
            return true;
        } else {
            Node node = new Node(data);
            Node cur = searchIndex(index);
            node.next = cur.next;
            cur.next = node;

        }
        return true;
    }

    @Override
    public boolean contains(int key) {
        Node cur = this.head;
        /*if(this.head==null){
            return false;
        }*/
        while (cur != null) {
            if (cur.data == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    //查找关键字key的前驱
//如果找不到,返回null
    private Node searchPre(int key) {
        Node pre = this.head;
        //头结点是要删除的数据节点
        if (pre.data == key) {
            return this.head;
        }
        while (pre.next != null) {
            if (pre.next.data == key) {
                return pre;
            }
            pre = pre.next;
        }
        return null;
    }

    @Override
    public int remove(int key) {
        int oldData = 0;
        Node pre = searchPre(key);
        if (pre == null) {
            throw new UnsupportedOperationException("不存在key节点");
        }
        if (pre == head && pre.data == key) {
            oldData = this.head.data;
            this.head = this.head.next;
            return oldData;
        }
        Node del = pre.next;
        oldData = del.data;//先保存
        pre.next = del.next;//删除节点
        return oldData;
    }

    @Override
    public void removeAllKey(int key) {
        if (this.head == null) {
            return;
        }
        Node pre = this.head;
        Node cur = this.head.next;
        while (cur != null) {
            if (cur.data == key) {
                pre.next = cur.next;
                cur = cur.next;
            } else {
                pre = cur;
                cur = cur.next;
            }
        }
        if (this.head.data == key) {
            this.head = this.head.next;
        }
    }

    @Override
    public int getLength() {
        Node cur = this.head;
        int length = 0;
        while (cur != null) {
            cur = cur.next;
            length++;
        }
        return length;
    }

    @Override
    public void display() {
        Node cur = this.head;
        while (cur != null) {
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    @Override
    public void clear() {
        Node cur = this.head;
        while (this.head != null) {
            this.head.next = null;
            this.head = cur;
            cur = cur.next;
        }

    }

测试类

public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        MySingleList mySingleList = new MySingleList();
        /*mySingleList.addFirst(10);
        mySingleList.addFirst(20);
        mySingleList.addFirst(30);
        mySingleList.addFirst(40);
        mySingleList.addFirst(50);
        mySingleList.display();*/

       /* mySingleList.addLast(10);
        mySingleList.addFirst(88);
        mySingleList.addLast(20);
        mySingleList.addLast(30);
        mySingleList.addFirst(99);
        mySingleList.addLast(40);
        mySingleList.display();*/

        mySingleList.addIndex(0,10);
        mySingleList.addIndex(1,99);
        mySingleList.addIndex(2,20);
        mySingleList.addIndex(3,30);
        mySingleList.addIndex(4,88);
        mySingleList.addLast(40);
        mySingleList.addIndex(6,88);
        mySingleList.display();//10 99 20 30 88 40 98
        MySingleList.Node res = mySingleList.reverseList();
        mySingleList.show(res);
        /*mySingleList.show(mySingleList.reverseList());*/
 /*       System.out.println(mySingleList.contains(20));
        System.out.println(mySingleList.contains(21));*/
 /*       mySingleList.remove(10);
        mySingleList.display();//99 20 30 88 40 98*/
 /*     mySingleList.removeAllKey(88);
        mySingleList.display();
*/
        /*mySingleList.clear();*/
       /* Thread.sleep(1000);
        System.out.println("Hello bit");*/


       /* mySingleList.addFirst(10);
        mySingleList.addFirst(20);
        mySingleList.addFirst(30);
        mySingleList.addFirst(40);
        System.out.println(mySingleList.getLength());*/

       /*mySingleList.addLast(10);
       mySingleList.addLast(20);
       mySingleList.addLast(30);
       System.out.println(mySingleList.contains(20));
*/

       /* mySingleList.addFirst(10);
        mySingleList.addFirst(20);
        mySingleList.addFirst(30);
        mySingleList.addFirst(40);
        mySingleList.addFirst(50);
        mySingleList.clear();
        mySingleList.display();*/

   }


}    
    
<think>我们参考引用中的信息来解答关于不带头节点的单向循环链表的问题。根据引用[1]:链表分为单链表(包括不带头节点、带头节点、循环单链表)和双向链表。引用[2]:头结点不是必需的,头指针始终指向链表的第一个结点(有头结点则指向头结点,无则指向第一个数据结点)。引用[3]:循环链表可以从任意结点出发访问全部结点,且访问尾结点的时间复杂度为O(1)。引用[5]提供了Java实现不带头结点的单向循环链表的示例代码。我们关注的是不带头节点的单向循环链表-特点:没有头结点,头指针直接指向第一个数据结点,且最后一个结点的指针域指向第一个结点(循环)。实现思路:-节点结构:每个节点包含数据域和指向下一个节点的指针。-链表结构:只需要一个头指针(head)和尾指针(tail)可选(引用[5]中同时使用了head和tail)。但为了操作方便(如在尾部插入),我们可以用尾指针或者只用一个头指针(但遍历到尾需O(n))。-操作:包括初始化、插入(头插、尾插、中间插入)、删除、遍历等。以下以Java语言实现一个不带头结点的单向循环链表,并实现基本操作。1.定义节点类:```javaclassNode{intdata;Nodenext;publicNode(intdata){this.data=data;this.next=null;//初始时next为null,但在链表中需要指向下一个节点或头节点形成循环}}```2.定义链表类,包含头指针和尾指针(可选,这里为了效率使用尾指针,但注意不带头节点):```javapublicclassCircularLinkedList{privateNodehead;//指向第一个节点privateNodetail;//指向最后一个节点publicCircularLinkedList(){head=null;tail=null;}}```3.实现操作:插入节点到头部:步骤:-创建新节点。-如果链表为空,则新节点的next指向自己,head和tail都指向该节点。-否则,新节点的next指向head,然后将head更新为新节点,同时让尾节点的next指向新节点(即新的头节点)。插入节点到尾部:-如果链表为空,同头部插入。-否则,将新节点插入到尾节点之后,然后更新尾节点为新节点,并让新节点的next指向头节点。具体代码实现如下(包括头插、尾插、删除头部节点、删除尾部节点、打印等):```java//节点类classNode{intdata;Nodenext;publicNode(intdata){this.data=data;}}//单向循环链表类(不带头节点)publicclassCircularLinkedList{privateNodehead;privateNodetail;publicCircularLinkedList(){head=null;tail=null;}//在头部插入节点publicvoidinsertAtHead(intdata){NodenewNode=newNode(data);if(head==null){//空链表head=newNode;tail=newNode;newNode.next=head;//循环指向自己}else{newNode.next=head;head=newNode;tail.next=head;//更新尾节点的next指向新的头节点}}//在尾部插入节点publicvoidinsertAtTail(intdata){NodenewNode=newNode(data);if(head==null){head=newNode;tail=newNode;newNode.next=head;}else{tail.next=newNode;//当前尾节点的next指向新节点tail=newNode;//更新尾节点tail.next=head;//新尾节点的next指向头节点}}//删除头部节点publicvoiddeleteAtHead(){if(head==null){System.out.println("链表为空,无法删除");return;}//如果只有一个节点if(head.next==head){head=null;tail=null;}else{head=head.next;tail.next=head;//更新尾节点的next指向新的头节点}}//删除尾部节点(稍微复杂,需要找到尾节点的前一个节点)publicvoiddeleteAtTail(){if(head==null){System.out.println("链表为空,无法删除");return;}//只有一个节点if(head.next==head){head=null;tail=null;}else{//找到尾节点的前一个节点Nodecurrent=head;while(current.next!=tail){current=current.next;}//此时current指向尾节点的前一个节点current.next=head;//跳过尾节点,指向头节点tail=current;//更新尾节点}}//打印链表publicvoidprintList(){if(head==null){System.out.println("链表为空");return;}Nodecurrent=head;System.out.print("循环链表:");do{System.out.print(current.data+"");current=current.next;}while(current!=head);System.out.println();}}```注意:删除尾部节点时,我们需要遍历链表来找到尾节点的前一个节点,时间复杂度为O(n)。如果希望优化,可以考虑使用双向链表,但这里我们讨论的是单向循环链表。此外,在循环链表中,遍历的终止条件不再是当前节点为null,而是当前节点回到头节点(即循环一圈)。上述代码实现了基本操作。我们可以测试一下:```javapublicstaticvoidmain(String[]args){CircularLinkedListlist=newCircularLinkedList();list.insertAtHead(2);list.insertAtHead(1);list.insertAtTail(3);list.insertAtTail(4);list.printList();//输出:循环链表:1234list.deleteAtHead();list.printList();//输出:循环链表:234list.deleteAtTail();list.printList();//输出:循环链表:23}```注意:在实现时,需要特别小心循环指针的维护,尤其是在插入和删除时。引用[5]中实现的不带头结点的单向循环链表(用于约瑟夫环问题)也提供了参考。以上实现满足了不带头节点的单向循环链表的基本操作。**相关问题:**1.如何在单链表中查找特定节点?2.循环链表的主要应用场景?3.如何在循环链表的任意位置插入和删除节点?4.循环链表的优点与缺点?</think> ### 不带头节点的单向循环链表实现及操作 #### 1. 基本概念 不带头节点的单向循环链表具有以下特点: - **无头节点**:头指针直接指向第一个数据节点 - **循环结构**:尾节点指针指向第一个数据节点 - **物理非连续**:数据元素通过指针连接实现逻辑顺序[^1] - **头指针作用**:始终指向链表第一个数据节点[^2] #### 2. 节点结构(Java实现) ```java class Node { int data; // 数据域 Node next; // 指针域 public Node(int data) { this.data = data; this.next = null; // 初始化时next为空 } } ``` #### 3. 链表核心操作 **头插法插入节点**[^4]: ```java void insertHead(Node head, int data) { Node newNode = new Node(data); if (head == null) { // 空链表:新节点自循环 newNode.next = newNode; head = newNode; } else { // 非空链表 newNode.next = head; // 找到尾节点并指向新节点 Node tail = head; while (tail.next != head) tail = tail.next; tail.next = newNode; head = newNode; // 更新头指针 } } ``` **遍历操作**: ```java void traverse(Node head) { if (head == null) return; Node current = head; do { System.out.print(current.data + " "); current = current.next; } while (current != head); // 循环终止条件[^3] } ``` **删除头节点**: ```java void deleteHead(Node head) { if (head == null) return; // 单节点链表 if (head.next == head) { head = null; } // 多节点链表 else { Node tail = head; while (tail.next != head) tail = tail.next; tail.next = head.next; // 尾节点指向新头 head = head.next; // 更新头指针 } } ``` #### 4. 实现优势 1. **空间效率**:省去头节点的存储开销 2. **操作统一**:头节点等同于数据节点[^5] 3. **循环优势**:$O(1)$时间访问尾节点[^3] 4. **内存灵活**:动态分配存储空间[^1] #### 5. 应用场景 - 约瑟夫环问题(Josephus problem)[^5] - 轮询任务调度 - 循环缓冲区实现 - 多人回合制游戏逻辑 **注意事项**: -链表判断条件:`head == null` - 循环终止须验证指针是否返回起点[^3] - 删除节点需维护循环结构 #### 示例操作流程 ``` 初始化:head = null 插入A:head → A (A.next=A) 插入B:head → B → A (A.next=B, B.next=A) 删除头:head → A (A.next=A) ``` **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值