快速找到未知长度单链表的中间节点

在讨论之前,我们首先首先要明白,什么是单链表?

单链表:链接方式存储的线性表

单链表的结点结构
  ┌──┬──┐
  │data│next│
  └──┴──┘ 
       data域--存放结点值的数据域
       next域--存放结点的直接后继的地址(位置)的指针域(链域)
注意:
     ①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
     ②每个结点只有一个链域的链表称为单链表(Single Linked List)。

那么我们先用java设计一下我们的单链表

public class MyLinkedList<E> {
    Node<E> first;
    Node<E> last;

    public MyLinkedList() {
        super();
    }

    public void add(E e) {
        if (first == null) {
            first = new Node<E>(e, null);
        } else {
            if (last == null) {
                last = new Node<E>(e, null);
                first.next = last;// 因为first和last还没建立关系,所以在这里要将他们的关系建立起来
            } else {
                Node<E> n = new Node<>(e, null);// 一个临时的引用n
                last.next = n;// 将last的next赋值为n的引用
                last = n;// 然后再将last重新赋值为n的引用
            }
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (Node<E> n = first; n != null; n = n.next) {
            sb.append(n.item).append(",");
        }
        sb.deleteCharAt(sb.length()-1).append("]");
        return sb.toString();
    }

    private static class Node<E> {
        E item;
        Node<E> next;

        Node(E element, Node<E> next) {
            this.item = element;
            this.next = next;
        }
    }
}

注意了,在这里我设计的单链表仅仅是为了符合我们讨论的问题,并不是完整的单链表,同时为了测试,我重写了toString方法。在这个单链表里面,我并没有实现List<E>这个接口,因为要实现的方法太多了,而且first和last这两个成员变量没有用private修饰符修饰,是不符合封装的思想,这里我一切从简。

我们先往里面添加一些数值,顺便测试下我们设计的单链表是否可以

public static void main(String[] args){
        MyLinkedList<Integer> list=new MyLinkedList<>();
        list.add(2);
        list.add(1);
        list.add(5);
        list.add(8);
        list.add(7);
        System.out.println(list.toString());
    }

运行结果:

没错,我们设计的单链表没问题

①快慢指针:一个指针每次按着顺序跳两次,而另一个指针只跳一次,当第一个指针跳到的元素为空是,那么第二个指针就处于中间的位置

/**
     * 获取中间元素
     *
     * @return
     */
    public E getMiddle() {
        Node<E> n1 = first;// 每次只走一步,慢指针
        Node<E> n2 = first;// 每次走两步,快指针

        L: while (true) {
            if (n2.next != null && n2.next.next != null) {
                n1 = n1.next;
                n2 = n2.next.next;
            } else {
                break L;
            }
        }
        return n1.item;
    }

将上面的代码添加到MyLinkedList.java里面,测试

public static void main(String[] args){
        MyLinkedList<Integer> list=new MyLinkedList<>();
        list.add(2);
        list.add(1);
        list.add(5);
        list.add(8);
        list.add(7);
        System.out.println(list.toString());
        System.out.println(list.getMiddle());
    }

结果如下:

时间: 2024-10-10 22:08:19

快速找到未知长度单链表的中间节点的相关文章

快慢指针原理--快速找到未知长度单链表的中间节点

package com.java.dataStruct; //节点类 public class Node<E> { E item; Node next; public Node(){ } public Node(E element){ this.item = element; } public Node(E element, Node next){ this.item = element; this.next = next; } } Node p1,r1; Node L1 = new Node

快速找到未知长度的单链表的中间结点

问题描述:快速找到未知长度的单链表的中间结点 普通方法:首先遍历一遍单链表,以确定单链表的长度L,然后再从头结点出发,循环L/2次,找到单链表的中间结点. 高效算法(快慢指针):设置两个指针,*search,*mid都指向单链表的头结点.其中*search指针的移动速度是*mid指针移动速度的2倍.当*search移动到链表末尾时,*mid刚好在中间结点.(标尺的思想) //快速得到单链表的中间结点 Status GetMidNode(LinkList &L,int &e){ LinkLi

单链表判断公共节点

单链表判断有无公共节点是个比较有趣的问题.这里所说的公共节点指的是完全相同的节点,不同与一般意义上的节点元素相同.相交单链表简单的都会是如下形式(有环除外): 粗略分析,容易想到就是暴力法,双重循环寻找公共节点. 关于单链表的判断有无公共节点,除了暴力法之外,还有很多方法可以尝试.下面简单列举几种. 可以尝试hash,如果两个节点的首地址相同,则该节点必定相同,可以以空间换取时间,先处理其中一个单链表,建立hash表,然后处理另外一个判断有无公共节点,时间复杂度为O(max(n,m)),空间复杂

求单链表的中间节点,用快慢指针

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Node* findMid(Node* &head) {     if(head == NULL||head->next == NULL)         return head;          Node* p = head;     Node* q = head;     while(q->next->next&&(q = q->next))     {         p = p-

C语言:【单链表】查找单链表的中间节点,要求只能遍历一次

#include<stdio.h> #include<assert.h> #include<stdlib.h> typedef int DataType; typedef struct SListNode {     DataType data;     struct SListNode* next; }SListNode; SListNode* BuyNode(DataType x) {     SListNode* next = (SListNode*)malloc

从无头单链表中删除节点

1.从无头单链表中删除节点 一个没有头指针的单链表.一个指针指向此单链表中间的一个节点(不是第一个也不是最后一个节点).将该节点删除. A-->B-->C-->D       =====>     A-->C-->D 问题解析:由于只能单向遍历,故与删除B节点,无法得知B的前驱A,即无法像普通删除中那样让A的next指向C; 这里有个技巧,将C当做B,而B复制成C,则删除C节点即可: 2.给定一个链表的头指针,要求只遍历一次,将单链表中的元素顺序反转过来. A-->

Leetcode:Swap Nodes in Pairs 单链表相邻两节点逆置

Given a linked list, swap every two adjacent nodes and return its head. For example, Given 1->2->3->4, you should return the list as 2->1->4->3. Your algorithm should use only constant space. You may not modify the values in the list, on

3.4 从无头单链表中删除节点

题目:有一个单链表,没有头指针,现在有一个指针指向这个链表的中间的一个节点,要求删除这个节点. 方法:由于没有办法寻求指针去找到要删除的这个节点的前一个节点. 所以要另想办法. 设立新的指针指向要删除的节点的后一个节点,然后把这两个节点里面的数据换一下!然后删除要删除节点的后一个节点! 这样 就ok了! 代码: void DeleteRandomNode(node *pCurrent) { assert(pCurrent != NULL); node *pNext = pCurrent->nex

单链表一[带头节点链表]

单链表实现分带头节点链表和不带头节点链表: 使用头文件如下: struct LinkNode {     void *x;      struct LinkNode *next; }; 一,带头节点的链表: 1,链表创建 程序说明: 1)函数调用形式:szyu_link_create0("AA", "BB", NULL);其中NULL结尾是在for循环的判断结束条件为x == NULL.使用NULL可以是for循环正常退出 2)程序先创建头节点head,并初始化he