剑指offer关于链表的一些操作(java)


import algorithd.LinkList.Node;

/**
*@author 风雨落
*@version 2017年12月16日下午6:21:29
*@title  java写链表尝试
*/

class LinkList {

    Node head;

    //添加数据
    public void add(int data){
        Node newNode = new Node(data);
        if(head==null){
            head = newNode;
        }else{
            Node p = head;
            while(p.next!=null){
                p = p.next;
            }
            p.next = newNode;
        }
    }

    //打印链表
    public void print(){
        Node p = head;

        while(p!=null){
            System.out.println(p.value);
            p = p.next;
        } 
    }
    //找到链表中的倒数第k个节点
    /**
     * 这里需要声明两个指针:即两个结点型的变量first和second,
     * 首先让first和second都指向第一个结点,
     * 然后让second结点往后挪k-1个位置,
     * 此时first和second就间隔了k-1个位置,
     * 然后整体向后移动这两个节点,直到second节点走到最后一个结点的时候,
     * 此时first节点所指向的位置就是倒数第k个节点的位置。时间复杂度为O(n)
     * @param index
     * @return
     */
    public boolean findLastNode(int index){
        Node p =  head;
        Node first =  p;
        Node second = p;
        int k = index;
        if(k==0){
            System.out.println("数据不合理");
            return false;
        }


        index--;

        while(index>0&&second.next!=null){
            second = second.next;
            index--;
        }
        if(index!=0){
            System.out.println("数据不合理");
            return false;
        }
        while(second.next!=null){
            first = first.next;
            second = second.next;
        }

        System.out.print("倒数第"+k+"个节点"+first.value);

        return true;
    }
    //两个有序列表合并  尤其要注意两个链表都为空、和其中一个为空的情况
    public LinkList combineSorted(LinkList ls){

        Node p = head;
        Node q = ls.head;
        LinkList newLs = new LinkList();
        Node newNode;
        if(p==null&&q==null){//两个链表均为空
            return newLs;
        }
        if(p==null){//单链表为空
            newLs = ls;
            return newLs;
        }
        if(q==null){
            newLs = this;
            return newLs;
        } 
        if(p.value<q.value){
            newLs.head = p;
            p = p.next;
        }else{
            newLs.head = q;
            q = q.next;
        } 
        newNode = newLs.head;
        while(p!=null){
            if(p.value<q.value){
                newNode.next = p;
                newNode = newNode.next;
                p = p.next;
            }else{
                newNode.next = q;
                newNode = newNode.next;
                q = q.next;
            }
        }
        //合并剩余节点
        while(q!=null){
            newNode.next = q;
            q = q.next;
            newNode = newNode.next;
        }
        return newLs;
    }
    //单链表的反转
    public LinkList reverse(){
        LinkList ls = this;
        Node cur,pre,next;
        cur = ls.head;
        if(cur==null||cur.next==null){//空链表或者单元素
            return ls;
        }

        //处理头节点
        next = cur.next;
        cur.next = null;
        pre = cur;
        cur = next;


        while(cur!=null){
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        ls.head = pre;
        return ls;
    }
    //判断一个链表是否有环
    public boolean hasCircle(){
        Node p,q;
        p = head;
        q = head;
        while(p!=null&&p.next!=null){
            p = p.next.next;
            q = q.next;
            if(p==q){
                return true;
            }
        }
        return false;
    }
    //找链表环的起始节点
    public void findCricleStart(){
        //首先要有环
        if(hasCircle()){
            //确定在环中的点
            Node p,q;
            p = head;
            q = head;
            Node eNode = head;
            while(p!=null&&p.next!=null){
                p = p.next.next;
                q = q.next;
                if(p==q){
                    eNode = p;
                    break;
                }
            }
            //确定环的长度
            p = eNode;
            int num = 0;
            while(p!=null){
                p=p.next;
                num++;
                if(p==eNode){
                    break;
                }
            }
            p = head;
            while((num--)!=0){
                p = p.next;
            }
            System.out.print(p.value);
        }
    }
    /**
     * 使用内部类,可以和外部类进行私有操作的相互访问
     * @author Administrator
     *
     * @param <Integer>
     */
    class Node{
        Integer value;
        Node next;
        public Node(Integer data){
            value = data;
            next = null;
        }
    }
}
public class Main1216 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
            LinkList ls = new LinkList();

            ls.print(); 
            LinkList ls1 = new LinkList();
            ls1.add(1);
            ls1.add(3);
            ls1.add(21); 
            Node p = ls1.head;
            while(p.next!=null){
                p = p.next;
            }
            p.next = ls1.head;
//          LinkList ls2 = ls.combineSorted(ls1); 
//          LinkList ls3 = ls1.reverse();
//          ls3.print();
            if(ls1.hasCircle()){
                System.out.println("有");
            }else{
                System.out.println("没有");
            }
            ls1.findCricleStart();
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值