数据结构—链表(二)

主要内容:

本次练习包括删除链表中的重复数据、找出单链表中倒数第K个元素、链表反转、从尾到头输出单链表、寻找单链表的中间节点。

package com.sf.linkedlist;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * Created by laxe on 2016/11/30.
 */

public class LinkedListDemo1 {
    static Node head=null;
    public static void main(String args[]){
        head=new Node(9);
        Node next1=new Node(3);
        Node next2=new Node(5);
        Node next3=new Node(4);
        Node next4=new Node(10);

        head.next=next1;
        next1.next=next2;
        next2.next=next3;
        next3.next=next4;
        showList(head);
        //deleteDuplecate();//删除重复元素
        //deleteDuplecate1();

        //Node key=findElem(1);//找到倒数第k个元素
        //System.out.println(key.val);

        //reverseIteratively();//反转链表


        //printListReversely(head);//逆序输出

        List<Node> list=findMid();//找到单链表的中间节点
        for(Node node:list) {
            System.out.println(node.val);
        }
        showList(head);
    }

//删除链表中的重复元素
    /**
     * 思路一:遍历链表,把遍历到的值存储到一个hashtable中,在遍历的过程中,如果发现该节点的值已经存在,那么删除该节点。
     *
     * */
    public static void deleteDuplecate(){
        if(head==null)
            return;

        Node tmp=head;
        Node pre=null;
        HashMap<Integer,Integer> hm=new HashMap<Integer, Integer>();
        while(tmp!=null){
            if(!hm.containsKey(tmp.val)){
                hm.put(tmp.val,1);
                pre=tmp;
            }else{
                pre.next=tmp.next;
            }
            tmp=tmp.next;
        }
    }

    /**
     * 思路二:
     * 双重循环遍历:
     * 外循环正常遍历链表,假设外循环当前遍历的元素是curr,
     * 内循环从curr开始遍历,看后面有没有和curr值一样的元素节点。如果有,那么删除
     *
     * */
    public static void deleteDuplecate1(){
        Node curr=head;
        while(curr!=null){
            Node tmp=curr;
            while(tmp.next!=null){
                if(tmp.next.val==curr.val){
                    tmp.next=tmp.next.next;
                }else{
                    tmp=tmp.next;
                }
            }
            curr=curr.next;
        }
    }

    /**
     * 思路三:
     * 双重循环遍历:
     * 外循环正常遍历链表,假设外循环当前遍历的元素是curr,
     * 内循环从head开始遍历,看后面有没有和curr值一样的元素节点。如果有,那么删除,内循环结束,因为前面与curr节点值相同的元素只会有一个。
     *
     * */
    //TODO

//如何找出单链表中倒数第K个元素
    /**
     * 思路1:遍历一遍链表求出链表长度n,找到倒数第k个,就是找到正数第n-k个。差不多进行了两次遍历
     * 思路2:从某个元素开始,遍历k个元素后正好到达链表尾,那么该元素就是要找的第k个元素。
     *        算法设计:从头开始,依次对链表的每一个节点元素进行测试,遍历k个元素后若达到链表尾,那么就找到了目标元素,这种方式也不是最优的。
     * 思路3:设置两个指针,两个指针相距k-1,并且同时往后移动,直到后面那个元素达到末尾,那么前面那个元素就是目标元素。只遍历一遍。
     *
     * */
    public static Node findElem(int k){
        if(k<1 || k>length())
            return null;
        Node first=head;
        Node second=head;
        for(int i=0;i<k-1;i++){
            second=second.next;
        }

        while(second.next!=null){
            first=first.next;
            second=second.next;
        }
        return first;
    }


//实现链表的反转
    /**
     * 假设有i,m,n三个节点。i->m->n
     * 那么在反转的过程中就是把指针箭头反转。
     * 如果将m->i,那么就没有指针指向n了,链表就断开了,所以,在反转的过程中需要在调整m的next之前,需要把n保存下来。
     * */
    public static void reverseIteratively(){
        Node pReversedHead=head;
        Node pNode=head;
        Node pPrev=null;
        while(pNode!=null){
            Node pNext=pNode.next;
            if(pNext==null)
                pReversedHead=pNode;
            pNode.next=pPrev;
            pPrev=pNode;
            pNode=pNext;
        }
        head=pReversedHead;
    }

//从尾到头输出单链表
    public static void printListReversely(Node head){
        if(head!=null){
            printListReversely(head.next);
            System.out.println(head.val);
        }
    }

//找到链表的中间元素
    /**
     * 思路1:第一次遍历,得出链表长度;第二次遍历,根据索引遍历到中间元素
     * 思路2:设置两个指针,一个快指针,一个慢指针。快指针每次走两步,慢指针一次走一步。
     *        当快指针达到链表尾时,慢指针正好到达中间
     *        链表长度若为偶数,则慢指针指向的元素和下一个元素都是中间元素;
     *        链表长度若为奇数,则慢指针指向的元素就是中间元素;
     *
     * */
    public static List<Node> findMid(){
        Node fast=head;
        Node slow=head;
        List<Node> list=new ArrayList<Node>();
        while(fast!=null && fast.next!=null && fast.next.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }

        if(length()%2==0) {
            list.add(slow);
            list.add(slow.next);
        }else{
            list.add(slow);
        }
        return list;
    }





    /**
     * 打印链表
     * */
    public static void showList(Node head){
        if(head==null)
            return;
        Node tmp=head;
        while(tmp!=null)
        {
            if(tmp.next!=null) {
                System.out.print(tmp.val+"->");
                tmp = tmp.next;
            }else{
                System.out.print(tmp.val);
                tmp = tmp.next;
            }
        }
        System.out.println();
    }

    /**
     * 获取链表的长度
     * */
    public static int length(){
        int length=0;
        Node tmp=head;
        while(tmp!=null){
            length++;
            tmp=tmp.next;
        }
        return length;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值