鏈表(Java)

鏈表常見的操作:

1厚棵、插入節(jié)點(diǎn)(頭插、尾插)
2蔼紧、刪除節(jié)點(diǎn)
3窟感、獲取鏈表長(zhǎng)度
4、逆序打印
5歉井、反轉(zhuǎn)鏈表
6柿祈、判斷鏈表是否有環(huán)
7、判斷鏈表是否相交
8、如果相交躏嚎,返回第一個(gè)開始相交的節(jié)點(diǎn)
9蜜自、查找單鏈表中第K個(gè)節(jié)點(diǎn)
10、尋找單鏈表的中間結(jié)點(diǎn)

代碼外加注釋如下

class LinkList{
    Node header;
    static class Node{
        int data;
        Node next;
        public Node(int data){
            this.data = data;
        }
    }
    
    /*
     * 頭插法
     * 被插入node的next指向header卢佣,則成為第一個(gè)
     * 將header移動(dòng)到頭部
     */
    public void addNodeHead(int data){
        Node newNode = new Node(data);
        if(header==null){
            header = newNode;
        }else{
            newNode.next = header;
            header = newNode;
        }
    }
    
    /**
     * 尾插法
     */
    public void addNodeEnd(int data){
        Node newNode = new Node(data);
        if(header==null){
            header = newNode;
        }else{
            Node temp = header;
            while(temp.next!=null){
                temp = temp.next;
            }
            temp.next = newNode;
        }
    }
/**
     * 鏈表刪除結(jié)點(diǎn):
     * 把要?jiǎng)h除結(jié)點(diǎn)的前結(jié)點(diǎn)指向要?jiǎng)h除結(jié)點(diǎn)的后結(jié)點(diǎn)重荠,即直接跳過待刪除結(jié)點(diǎn)
     * @param index
     * @return
     */
    public boolean deleteNode(int index){
        if(index<1 || index>getLength(header)){//待刪除結(jié)點(diǎn)不存在
            return false;
        }
        if(index == 1){//刪除頭結(jié)點(diǎn)
            header = header.next;
            return true;
        }
        Node preNode = header;
        Node curNode = preNode.next;
        int i = 1;
        while(curNode != null){
            if(i==index){//尋找到待刪除結(jié)點(diǎn)
                preNode.next = curNode.next;//待刪除結(jié)點(diǎn)的前結(jié)點(diǎn)指向待刪除結(jié)點(diǎn)的后結(jié)點(diǎn)
                return true;
            }
            //當(dāng)先結(jié)點(diǎn)和前結(jié)點(diǎn)同時(shí)向后移
            preNode = preNode.next;
            curNode = curNode.next;
            i++;
        }
        return true;
    }
    
    /**
     * 長(zhǎng)度
     * @param header
     * @return
     */
    public int getLength(Node header){
        int num = 0;
        while(header!=null){
            num++;
            header = header.next;
        }
        return num;
    }
    
    /**
     * 從尾到頭打印鏈表
     * 建棧
     */
    public void reversePrintLink(Node node){
        Stack<Node> stack = new Stack<Node>();
        while(node!=null){
            stack.push(node);
            node = node.next;
        }
        while(!stack.isEmpty()){
            System.out.print(stack.pop().data+" ");
        }
        System.out.println();
    }
    
    /**
     * 從尾到頭打印鏈表
     * 遞歸
     */
    public void reversePrintLink1(Node node){
        if(node!=null){
            reversePrintLink1(node.next);
            System.out.print(node.data+" ");
        }
    }
    
    /**
     * 正序打印
     */
    public void printLink(Node node){
        while(node!=null){
            System.out.print(node.data+" ");
            node = node.next;
        }
    }
    
    /**
     * 反轉(zhuǎn)鏈表
     */
    public void reverseLink(){
        Node curNode = header;
        Node preNode = null;
        Node nextNode = null;
        while(curNode!=null){
            nextNode = curNode.next;//保留下一個(gè)節(jié)點(diǎn)(因?yàn)橐獢嚅_下面了)
            curNode.next = preNode;//反轉(zhuǎn)指針到前面
            //移動(dòng)節(jié)點(diǎn)為了繼續(xù)下一次保存、斷開虚茶、反轉(zhuǎn)
            preNode = curNode;
            curNode = nextNode;
        }
        header = preNode;
    }
    
    /**
     * 創(chuàng)建有環(huán)鏈表只為測(cè)試用
     */
    public void createRing(){
        header = new Node(1);
        header.next = header;
    }
    
    /**
     * 是否有環(huán)
     * 設(shè)置快指針和慢指針戈鲁,慢指針每次走一步,快指針每次走兩步
     * 當(dāng)快指針與慢指針相等時(shí)嘹叫,就說明該鏈表有環(huán)
     */
    public boolean isRing(){
        if(header == null){
            return false;
        }
        Node slow = header;
        Node fast = header;
        if(fast.next!=null && fast.next.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 創(chuàng)建添加節(jié)點(diǎn)的鏈表方法婆殿,為測(cè)試相交
     */
    public void add(Node node){
        if(node==null){
            return;
        }
        if(header==null){
            header = node;
        }else{
            node.next = header;
            header = node;
        }
    }
    
    /**
     * 兩個(gè)鏈表是否相交
     * 兩個(gè)鏈表相交,則它們的尾結(jié)點(diǎn)一定相同罩扇,比較兩個(gè)鏈表的尾結(jié)點(diǎn)是否相同即可
     */
    public static boolean isCross(Node head1,Node head2){
        if(head1==null||head2==null){
            return false;
        }
        Node temp1 = head1;
        Node temp2 = head2;
        while(temp1.next!=null){
            temp1 = temp1.next;
        }
        while(temp2.next!=null){
            temp2 = temp2.next;
        }
        return temp1 == temp2;
    }
    
     /**
     * 如果鏈表相交婆芦,求鏈表相交的起始點(diǎn):
     * 1、首先判斷鏈表是否相交喂饥,如果兩個(gè)鏈表不相交消约,則求相交起點(diǎn)沒有意義
     * 2、求出兩個(gè)鏈表長(zhǎng)度之差:len=length1-length2
     * 3员帮、讓較長(zhǎng)的鏈表先走len步
     * 4或粮、然后兩個(gè)鏈表同步向前移動(dòng),沒移動(dòng)一次就比較它們的結(jié)點(diǎn)是否相等捞高,第一個(gè)相等的結(jié)點(diǎn)即為它們的第一個(gè)相交點(diǎn)
     */
    public static Node findFirstCrossPoint(LinkList linkedList1, LinkList linkedList2){
        //鏈表不相交
        if(!isCross(linkedList1.header,linkedList2.header)){
            return null;
        }else{
            int length1 = linkedList1.getLength(linkedList1.header);//鏈表1的長(zhǎng)度
            int length2 = linkedList2.getLength(linkedList2.header);//鏈表2的長(zhǎng)度
            Node temp1 = linkedList1.header;//鏈表1的頭結(jié)點(diǎn)
            Node temp2 = linkedList2.header;//鏈表2的頭結(jié)點(diǎn)
            int len = length1 - length2;//鏈表1和鏈表2的長(zhǎng)度差
            
            if(len > 0){//鏈表1比鏈表2長(zhǎng)被啼,鏈表1先前移len步        
                for(int i=0; i<len; i++){
                    temp1 = temp1.next;
                }
            }else{//鏈表2比鏈表1長(zhǎng),鏈表2先前移len步
                for(int i=0; i<-len; i++){
                    temp2 = temp2.next;
                }
            }
            //鏈表1和鏈表2同時(shí)前移,直到找到鏈表1和鏈表2相交的結(jié)點(diǎn)
            while(temp1 != temp2){
                temp1 = temp1.next;
                temp2 = temp2.next;
            }
            return temp1;
        }
    }
    
    /**
     * 查找單鏈表中第K個(gè)節(jié)點(diǎn)
     * 第二種解法是快慢指針,主要思路就是使用兩個(gè)指針棠枉,先讓前面的指針走到正向第k個(gè)結(jié)點(diǎn),
     * 后面的指針才走泡挺,這樣前后兩個(gè)指針的距離差是k-1辈讶,之后前后兩個(gè)指針一起向前走,
     * 前面的指針走到最后一個(gè)結(jié)點(diǎn)時(shí)娄猫,后面指針?biāo)附Y(jié)點(diǎn)就是倒數(shù)第k個(gè)結(jié)點(diǎn)
     */
    public Node getKNode(Node head,int k){
        if(k<0||k>getLength(header)){
            return null;
        }
        Node first = head;
        Node last = head;
        for(int i=1;i<k;i++){
            first = first.next;
        }
        while(first.next!=null){
            first = first.next;
            last = last.next;
        }
        return last;
    }
    
    /**
     * 尋找單鏈表的中間結(jié)點(diǎn):
     * 方法一贱除、先求出鏈表的長(zhǎng)度,再遍歷1/2鏈表長(zhǎng)度媳溺,尋找出鏈表的中間結(jié)點(diǎn)
     * 方法二月幌、:
     * 用兩個(gè)指針遍歷鏈表,一個(gè)快指針悬蔽、一個(gè)慢指針扯躺,
     * 快指針每次向前移動(dòng)2個(gè)結(jié)點(diǎn),慢指針一次向前移動(dòng)一個(gè)結(jié)點(diǎn),
     * 當(dāng)快指針移動(dòng)到鏈表的末尾录语,慢指針?biāo)诘奈恢眉礊橹虚g結(jié)點(diǎn)所在的位置 
     */
    public Node findMiddleNode(){
        Node slowPoint = header;
        Node quickPoint = header;
        //鏈表結(jié)點(diǎn)個(gè)數(shù)為奇數(shù)時(shí),返回的是中間結(jié)點(diǎn)倍啥;鏈表結(jié)點(diǎn)個(gè)數(shù)為偶數(shù)時(shí),返回的是中間兩個(gè)結(jié)點(diǎn)中的前一個(gè)
        while(quickPoint.next != null && quickPoint.next.next != null){
            slowPoint = slowPoint.next;
            quickPoint = quickPoint.next.next;
        }
        return slowPoint;
    }

}

測(cè)試代碼如下:


public class LinkTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //測(cè)試尾插法和遞歸從尾達(dá)到頭打印
        System.out.println("---------測(cè)試尾插法和遞歸打印----------");
        LinkList mLink = new LinkList();
        mLink.addNodeEnd(1);
        mLink.addNodeEnd(2);
        mLink.addNodeEnd(3);
        System.out.println(mLink.getLength(mLink.header));
        mLink.reversePrintLink1(mLink.header);
        System.out.println();
        //測(cè)試頭插法和棧從尾達(dá)到頭打印
        System.out.println("---------測(cè)試頭插法和棧打印----------");
        LinkList mLink1 = new LinkList();
        mLink1.addNodeHead(1);
        mLink1.addNodeHead(2);
        mLink1.addNodeHead(3);
        mLink1.addNodeHead(4);
        System.out.println(mLink1.getLength(mLink1.header));
        mLink1.reversePrintLink(mLink1.header);
        System.out.println();
        //測(cè)試反轉(zhuǎn)
        System.out.println("---------測(cè)試反轉(zhuǎn)----------");
        LinkList mLink2 = new LinkList();
        mLink2.addNodeEnd(5);
        mLink2.addNodeEnd(6);
        mLink2.addNodeEnd(7);
        mLink2.addNodeEnd(8);
        mLink2.reverseLink();
        mLink2.printLink(mLink2.header);
        System.out.println();
        //測(cè)試有環(huán)
        System.out.println("---------測(cè)試有環(huán)----------");
        LinkList mLink3 = new LinkList();
        mLink3.createRing();
        System.out.println("是否有環(huán):"+mLink3.isRing());
        System.out.println("---------測(cè)試相交----------");
        LinkList mLink4 = new LinkList();
        LinkList mLink5 = new LinkList();
        LinkList.Node node = new LinkList.Node(0);
        mLink4.addNodeHead(1);
        mLink5.addNodeHead(1);
        mLink4.add(node);
        mLink5.add(node);
        mLink5.addNodeHead(2);
        System.out.println("是否相交:"+LinkList.isCross(mLink4.header,mLink5.header));
        System.out.println("相交的起始節(jié)點(diǎn):"+LinkList.findFirstCrossPoint(mLink4, mLink5).data);
        System.out.println("---------測(cè)試返回倒數(shù)第k個(gè)節(jié)點(diǎn)----------");
        LinkList mLink6 = new LinkList();
        mLink6.addNodeEnd(1);
        mLink6.addNodeEnd(2);
        mLink6.addNodeEnd(3);
        mLink6.addNodeEnd(4);
        mLink6.addNodeEnd(5);
        mLink6.addNodeEnd(6);
        System.out.println(mLink6.getKNode(mLink6.header, 2).data);
    }

}

打印如下:

---------測(cè)試尾插法和遞歸打印----------
3
3 2 1 
---------測(cè)試頭插法和棧打印----------
4
1 2 3 4 

---------測(cè)試反轉(zhuǎn)----------
8 7 6 5 
---------測(cè)試有環(huán)----------
是否有環(huán):true
---------測(cè)試相交----------
是否相交:true
相交的起始節(jié)點(diǎn):0
---------測(cè)試尾插法和遞歸打印----------
5

相關(guān)博文:
java實(shí)現(xiàn)單鏈表常見操作 ----方法思路標(biāo)注詳細(xì)
面試中的Java鏈表---這個(gè)是一個(gè)面試題一個(gè)解
http://www.reibang.com/p/6ebedde370b0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末澎埠,一起剝皮案震驚了整個(gè)濱河市虽缕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒲稳,老刑警劉巖氮趋,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異江耀,居然都是意外死亡剩胁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門决记,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摧冀,“玉大人,你說我怎么就攤上這事系宫∷靼海” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵扩借,是天一觀的道長(zhǎng)椒惨。 經(jīng)常有香客問我,道長(zhǎng)潮罪,這世上最難降的妖魔是什么康谆? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮嫉到,結(jié)果婚禮上沃暗,老公的妹妹穿的比我還像新娘。我一直安慰自己何恶,他們只是感情好孽锥,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著细层,像睡著了一般惜辑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疫赎,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天盛撑,我揣著相機(jī)與錄音,去河邊找鬼捧搞。 笑死抵卫,一個(gè)胖子當(dāng)著我的面吹牛狮荔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播陌僵,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼轴合,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了碗短?” 一聲冷哼從身側(cè)響起受葛,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎偎谁,沒想到半個(gè)月后总滩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巡雨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年闰渔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铐望。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冈涧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出正蛙,到底是詐尸還是另有隱情督弓,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布乒验,位于F島的核電站愚隧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏锻全。R本人自食惡果不足惜狂塘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鳄厌。 院中可真熱鬧荞胡,春花似錦、人聲如沸了嚎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)新思。三九已至,卻和暖如春赘风,著一層夾襖步出監(jiān)牢的瞬間夹囚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工邀窃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荸哟,地道東北人假哎。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鞍历,于是被迫代替她去往敵國(guó)和親舵抹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容