資料結構之Java單鏈表反轉
本文為資料結構基礎,研究得不是很深。用Java實現單鏈表的反轉,雖然本文研究得不是很深,但是因為是資料結構,所以必須是在對Java記憶體比較清楚的情況下才能真正的搞懂吃透,如果對Java記憶體不夠清楚,那最多隻能學形而不能學其內在。
首先我們要搞清楚連結串列是啥玩意兒?先看看定義:
講連結串列之前我們先說說Java記憶體的分配情況:我們new物件的時候,會在java堆中為物件分配記憶體,當我們呼叫方法的時候,會將方法載入到方法區,在方法區儲存了載入類的資訊,常量,靜態變數等等。搞明白這個我們再來講連結串列。
連結串列是一種物理儲存單元
這兒著重宣告:在Java中,沒有地址一說,只有hashCode。其實hashCode就是通過演算法,將每一個物件的地址算成一個code轉成一個特有的字串。當我們沒有複寫Object類的toString方法的時候,該類的物件呼叫toString方法,打印出來,或者不呼叫toString方法,直接列印該類的物件,其實就是將hashCode打印出來了。這個hashCode就相當於是記憶體了。
好了搞懂了這些我們就可以來看看例項了:
節點Node類,其實節點就是我們的物件,每一個節點就是一個物件。
/** * 其實一個節點就對應我們java中的一個物件,我們在分析的時候需要注意除了next要儲存一個地址外,自己也是物件自己也有地址 * Created by PICO-USER dragon on 2017/3/16. */ public class Node { //資料域儲存資料 private int data; //指標域用於儲存下一個節點的地址 private Node next; public Node(int data) { this.data = data; } public int getData() { return data; } public void setData(int data) { this.data = data; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } }
反轉連結串列的方法,當傳入的節點為null的時候,直接染回null。如果只有一個節點,頭尾都是它,直接返回該節點
public static Node reverseList(Node head) { if (head == null) { return null; } if (head.getNext() == null) { return head; } //previous上一個節點 Node preNode = null; //current節點當前節點,並讓它指向傳進來的物件所在地址(是儲存該物件的地址,不是它的next值) Node curNode = head; //next節點下一個節點 Node nextNode = null; while (curNode != null) { //讓next節點指向後一個節點所在地址,並改變新地址的值(包括data,next) nextNode = curNode.getNext(); if (nextNode != null) { System.out.print("nextNode data :" + nextNode.getData() + " next :" + nextNode.getNext() + " " + nextNode + "\n"); } //將current節點儲存的地址(也就是next)的值改為preNode節點所指向的地址(這樣就把指向箭頭反轉了)這兒有個誤區 //注意:是將preNode指向的地址給curNode的next,不是把preNode的next給它。 curNode.setNext(preNode); if (curNode != null) { System.out.print("curNode data :" + curNode.getData() + " next :" + curNode.getNext() + " " + curNode + "\n"); } //讓previous節點指向的地址向後移動一個單位,並改變新地址的值(包括data,next) preNode = curNode; if (preNode != null) { System.out.print("preNode data :" + preNode.getData() + " next :" + preNode.getNext() + " " + preNode + "\n"); } //讓current節點的索引向後移動一個單位,並改變新地址的值包括(data,next) curNode = nextNode; if (curNode != null) { System.out.print("curNode data :" + curNode.getData() + " next :" + curNode.getNext() + " " + curNode + "\n"); } System.out.print("-----------------------\n"); } return preNode; }
public class MainRun { public static void main(String[] arg0) { //建立連結串列的節點,建立了三個物件,那就是三個節點 Node node0 = new Node(1); Node node1 = new Node(2); Node node2 = new Node(3); //將這些節點,串連起來形成連結串列 node0.setNext(node1); node1.setNext(node2); //連結串列的頭結點代表了該連結串列,因為頭結點能找到第二個,第二個能找到第三個,依次找下去,全都找到了 Node head1 = node0; //先列印反轉之前的連結串列的值,將hashCode一起打印出來,方便去每一行程式碼都對誰做了什麼操作 while (head1 != null) { System.out.print("data :" + head1.getData() + " next :" + head1.getNext() + " " + head1.toString() + "\n"); head1 = head1.getNext(); } System.out.print("---++++++-----\n"); //注意了,我們是從頭開始反轉,所以這兒不能用head1,因為head1在上面的while迴圈中已經成為最後一個節點了 Node oldHead = node0; Node newHead = reverseList(oldHead); //列印反轉後的節點 while (newHead != null) { System.out.print("data :" + newHead.getData() + " next :" + newHead.getNext() + " " + newHead + "\n"); newHead = newHead.getNext(); } }
看看執行結果:
下面給出分析結果,我自己用筆畫的,網友可以根據這個分析步驟,跟著while迴圈的程式碼一句一句往下分析,每一行程式碼執行之後改動的值是什麼?多看看,多分析分析就通了。
第二種方法:遞迴呼叫實現單鏈表反轉
/** * 因為遞迴的思想是直接更改當前節點的next的值為前一個節點所在的地址,所以需要用到兩個引數,當前節點和前一個節點, * 這兒給外面用就只給一個方法,我們再自己封一個兩個引數的方法。 * * @param head * @return */public static Node reverseList2(Node head) { return reverseListRecursively(null, head);}/** * 遞迴呼叫實現的思想很簡單,就是直接改變curNode的next的值。原本是指向後面一個節點的,現在需要改為前一個節點。* 所以參與演算法的人只有當前節點和當前的前一個節點,而下一個節點的作用只是用於讓需要更換next的物件往後面移動* * @param preNode* @param curNode* @return*/public static Node reverseListRecursively(Node preNode, Node curNode) { if (curNode == null) { return null; } if (curNode.getNext() == null) { curNode.setNext(preNode); return curNode; } //將curNode中儲存的地址改成前一個節點所在的地址curNode.setNext(preNode); //如果當前節點有下一個節點就將該節點拿出來Node nextNode = curNode.getNext(); //遞迴呼叫本方法,相當於讓preNode和curNode指向的地址都向後移動一個單位,直到所有的節點都將自己儲存的地址改為前一個為止Node newNode = reverseListRecursively(curNode, nextNode); return newNode;}
public static void main(String[] arg0) { //建立連結串列的節點,建立了三個物件,那就是三個節點 Node node0 = new Node(1); Node node1 = new Node(2); Node node2 = new Node(3); //將這些節點,串連起來形成連結串列 node0.setNext(node1); node1.setNext(node2); //連結串列的頭結點代表了該連結串列,因為頭結點能找到第二個,第二個能找到第三個,依次找下去,全都找到了 Node head1 = node0; //先列印反轉之前的連結串列的值,將hashCode一起打印出來,方便去每一行程式碼都對誰做了什麼操作 while (head1 != null) { System.out.print("data :" + head1.getData() + " next :" + head1.getNext() + " " + head1.toString() + "\n"); head1 = head1.getNext(); } System.out.print("---++++++-----\n"); //注意了,我們是從頭開始反轉,所以這兒不能用head1,因為head1在上面的while迴圈中已經成為最後一個節點了 Node oldHead = node0; Node newHead = reverseList2(oldHead); //列印反轉後的節點 while (newHead != null) { System.out.print("data :" + newHead.getData() + " next :" + newHead.getNext() + " " + newHead + "\n"); newHead = newHead.getNext(); } }
相關推薦
資料結構之Java單鏈表反轉
本文為資料結構基礎,研究得不是很深。用Java實現單鏈表的反轉,雖然本文研究得不是很深,但是因為是資料結構,所以必須是在對Java記憶體比較清楚的情況下才能真正的搞懂吃透,如果對Java記憶體不夠清楚,那最多隻能學形而不能學其內在。 首先我
java資料結構之迴圈單鏈表
直接上程式碼舉例說明: public class CircularLinkedList { //java中迴圈單鏈表 private class Node {//建立一個內部節點類 private Node next = null; private Objec
資料結構之靜態單鏈表
靜態連結串列L儲存 遊標 cur 5 2 3 4 0 6 7 .... 1 資料 data A
資料結構之——關於單鏈表的頭插法和尾插法的程式碼和思路
頭插法 思路:每次插入都在第一個節點之前,頭結點之後,那每次插入時的賦值就只要將頭結點的地址賦給插入的節點,然後將插入的節點的地址依次給後面節點就可以了。 1、定義一個要插入的節點q 2、q->data內給值e 3、q->next = p->nex
資料結構之迴圈單鏈表(C++實現)
基本的概念與連結串列相同,不同的是 最後一個鏈結點的指標指向頭部 形成了迴圈連結串列#include <iostream> using namespace std; class Node { public: Node *next; int data;
資料結構之鏈式表的實現--單鏈表(C語言)
學習參考: 嚴蔚敏: 《資料結構-C語言版》 基本操作: 單鏈表的建立 新增結點(頭插法) 新增結點(尾插法) 單鏈表的輸出 單鏈表的修改 單鏈表的插入 單鏈表的刪除 單鏈表按
資料結構學習(二)——單鏈表的操作之頭插法和尾插法建立連結串列
連結串列也是線性表的一種,與順序表不同的是,它在記憶體中不是連續存放的。在C語言中,連結串列是通過指標相關實現的。而單鏈表是連結串列的其中一種,關於單鏈表就是其節點中有資料域和只有一個指向下個節點的指標域。建立單鏈表的方法有兩種,分別是頭插法和尾插法。 所謂頭插法,就是按節
資料結構之雜湊表的java實現
雜湊表是一種資料結構,提供快速的插入和查詢功能。雜湊表基於陣列儲存資料,因此能在O(1)時間內定位資料。關鍵字值通過雜湊函式對映為陣列下標。缺點就是陣列建立後容量固定,如果資料較多需要不斷擴充套件其長度。如何將關鍵字轉換為陣列下標?這個操作是通過雜湊函式完成的。比如,下面就
C++數據結構之傳統單鏈表
fad div class for reverse while 結點 next using 這幾天有空重寫一下數據結構,從單鏈表開始吧,這個是C++版本的,後面會根據情況是否補充上C版本的。 這個文章寫了之後,也查看了網絡上其他的數據結構寫法,發現大家的寫法多多少少都有
資料結構與演算法——單鏈表(一)
單鏈表的頭插法,插入時就是逆序。 InsertList()還不完善。 #include<stdio.h> #include<stdlib.h> #define ERROR 0 #define OK 1 typedef int Status ; typedef int
資料結構 筆記:單鏈表的具體實現
LinkList設計要點 -類模板,通過頭結點訪問後繼結點 -定義內部結點型別Node,用於描述資料域和指標域 -實現線性表的關鍵操作(增,刪,查,等) template<typename T> class LinkList : public List<T>
資料結構 筆記:單鏈表的遍歷與優化
如何遍歷單鏈表中的每一個數據元素? 為單鏈表提供新的方法,線上性時間內完成遍歷 設計思路(遊標) -在單鏈表的內部定義一個遊標(Node* m_current) -遍歷開始前將遊標指向位置為0的資料元素 -獲取遊標指向的資料元素 -通過結點中的next指標移動遊標 提供一
java 單鏈表反轉 遞迴法 遍歷法
以下是一個例子 package com.haha.demo.util; public class node { static class Node { Integer data; Node next; } static Node readyNode() { Node
資料結構之廣義線性表
陣列(定義、順序儲存結構) 矩陣的壓縮儲存 廣義表 陣列的順序儲存(將二維的陣列壓縮要一維儲存) 行優先,低下標(aij的位序為k<以1作為開始>,每行n個元素): k = (i - 1) * n + (j - 1) + 1 = (i
演算法題系列之三 - 單鏈表反轉
問題: 實現單鏈表反轉 答案: 連結串列準備 class Node { private int Data;// 資料域 private Node Next;// 指標域 public Node(int Data) { // super(); this.Data = Da
資料結構實驗三單鏈表學生資訊
#include<iostream> #include<stdlib.h> using namespace std; class Student {private: struct Node {char name[20]; char age[4]; int nu
java 單鏈表反轉
連結:https://www.jianshu.com/p/d201e6a00e3f .準備連結串列 準備一個由DataNode組成的單向連結串列,DataNode如下: public class DataNode { private int data; private
資料結構之靜態順序表和動態順序表
@Sock對靜態順序表和動態順序表的總結 簡單概括他們的異同點 相同點:記憶體空間連續, 資料順序儲存 不同點:它們所佔記憶體空間的位置不同, 靜態定義一個順序表, 順序表所佔的記憶體空間開闢在記憶體的靜態區, 即所謂的函式棧上, 隨著函式呼叫的結束, 這塊記憶體區域會被系統自動
資料結構之動態順序表
動態順序表 動態順序表是跟靜態順序表大體相似,有些地方是不同的,動態順序表是在動態變化中,當我們的所需的記憶體不夠時,它會自動開闢一個我們需要的空間,來供我們使用。 動態順序表與靜態順序表的不同在於初始化/銷燬/所有插入,其他和靜態順序表完全一樣。 定義一個結構體 先將我們需
資料結構之靜態順序表
title: 資料結構之靜態順序表 date: 2018-11-09 14:21:51 tags: C-資料結構 靜態順序表屬於資料結構開始的一種基本結構 首先我們要知道資料結構的概念 資料結構 資料的組織關係 演算法 為了達到特定的目的的一系列過程。在這個過程中又