數據結構:老是爲了完成一個功能或者目的寫程序,但無論什麼程序、代碼實際上都是一些指令的集合,說白了就是在描述「怎麼作」,而光知道怎麼作還只是問題的一半,還要知道「作什麼」,也就是剛纔那些指令的對象是誰,天然確定是相關的數據,好比說學生信息管理中,指令是增長學生,那他的對象就是學生信息這種數據,指令是成績統計,那對象就是學生的成績數據,而在咱們的程序中,數據也必需要有一種很明確的組織表示方式,只要這樣咱們才能在這種具體明確的實體上編寫指令,好比說學生數據能夠定義爲一個多維的數組,只有這樣咱們再寫增長學生時,才能知道具體增長就是增長一個數組元素併爲其賦值。因此數據結構就是相互之間有聯繫的具備某種組織方式的數據集合。php
抽象數據類型相比較數據結構要具體一些,咱們光有了數據結構還不夠,由於數據是各類各樣的,對於不一樣數據,咱們能採起的方法也不同,好比說學生數據能夠增減,成績數據能夠進行算數運算,可是爲何說抽象呢,也就說他並非具體整型仍是字符型這種基本類型,而是咱們根據咱們要解決的實際問題,對應現實世界所描述的一種和現實世界中的實體對應的數據類型,並且這種抽象的數據類型還包括可以對於他實行的操做,好比說咱們定義一種數據類型叫「學生」,具體的數據我能夠定義一中相似表的結構存儲,並且還要定義一些操做,好比說添加學生,刪除學生,這兩部分就共同組成了「學生」這個抽象的數據類型。html
1.向鏈表中添加元素。判斷一個鏈表已經到達末尾的依據是該結點的next引用已經爲Null,因此要向末尾添加一個結點,先要把新增結點放在最後,再把末尾結點向後移位,具體操做過程以下圖:
java
代碼以下:node
/** * 向指定鏈表添加元素的方法 * @param obj 插入的元素 */ public void add(Object obj){ Node node=new Node(obj);//新建結點 if(head==null){//若是鏈表爲空 head = node; }else{ last.next=node;//先把新增結點放在最後 } last=node;//再把最後一個結點向後移位 }
2.插入元素。要插入一個新元素首先要建立一個新結點來存放它,而在具體實現的時候最讓人頭疼的時候無疑是怎樣找到指定位置的索引了,這裏所說的方法在下面的其餘操做基本上都是這樣衍生的,先了解一下插入結點的具體實現,根據這個結構的邏輯定義,若是咱們要在結點A以後插入一個結點,那麼就還須要修改結點A的next引用,實際上就是讓A結點的next引用指向新增結點的元素域,而後再讓新增結點的next引用指向A本來next結點(B)的元素域,用圖來表示更加直觀:git
代碼以下:web
/** * 向鏈表中插入新元素的方法 */ public void insert(int index,Object obj){ Node node=head; int j=0; while(node!=null&&j<index-2){ //查找到第index-1個元素 node=node.next; j++; } Node sert=new Node(obj);//被插入的結點 sert.next=node.next; node.next=sert; }
3.刪除元素。知道了插入元素的具體操做以後,刪除元素就顯得相對簡單了,好比說咱們要刪除一個結點b,就是要使這個結點失去引用,可是注意不要直接寫b=b.next,這樣的話b的引用仍是存在,並且還會出現另外一種錯誤,如圖所示,正確的刪除結點的方法以下:
數組
代碼以下:數據結構
/** * 刪除指定位置的結點 * @param index 索引 */ public void delete(int index){ Node node=head; int j=0; while(node!=null&&j<index-2){ //查找到第i-1個元素 node=node.next; j++; } node.next=node.next.next;//刪除第index個元素 }
4.最後就是修改元素了。
代碼以下:函數
/** * 改變指定位置的元素 * @param index 索引 * @param obj */ public void modify(int index,Object obj){ Node node=head; int j=0; while(node!=null&&j<index-1){ //找到第index個結點 node=node.next; j++; } node.obj=obj; }
單鏈表(單向鏈表):由兩部分組成 數據域(Data)和結點域(Node),單鏈表就像是一條打了不少結的繩子,每個繩結至關於一個結點,每一個節結點間都有繩子鏈接,這樣原理的實現是經過Node結點區的頭指針head實現的,每一個結點都有一個指針,每一個節點指針的指向都是指向自身結點的下一個結點,最後一個結點的head指向爲null,這樣一來就連成了上述所說繩子同樣的鏈,對單鏈表的操做只能從一端開始,若是須要查找鏈表中的某一個結點,則須要從頭開始進行遍歷。
學習
雙鏈表(雙向鏈表):雙鏈表和單鏈表相比,多了一個指向尾指針(tail),雙鏈表的每一個結點都有一個頭指針head和尾指針tail,雙鏈表相比單鏈表更容易操做,雙鏈表結點的首結點的head指向爲null,tail指向下一個節點的tail;尾結點的head指向前一個結點的head,tail 指向爲null,是雙向的關係;
雙向鏈表的節點類代碼:
public class Node { //存儲的數據 private Object data; //前一個節點 private Node prev; //後一個節點 private Node next; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public Node getPrev() { return prev; } public void setPrev(Node prev) { this.prev = prev; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } //定義構造函數 public Node(){ } public Node(Object data, Node prev, Node next) { super(); this.data = data; this.prev = prev; this.next = next; } }
雙向鏈表的部分具體實現代碼:
//實現雙向鏈表 public class myDoubleLinkImpl { //記錄鏈表的節點數 int length=0; //定義上一個節點 private Node header; //定義下一個節點 private Node tail; public myDoubleLinkImpl(){ //定義的一個空的鏈表 header=null; tail=null; length=0; } //獲取鏈表的節點值 public int getLength() { return length; } //向鏈表中添加值 public void add(Object data) { //判斷鏈表是不是空的哈 if(header==null) { header=new Node(data,null,null); tail=header; length++; }else{ //非空鏈表哈 Node tempNode=new Node(data,tail,null); tail.setNext(tempNode); tail=tempNode; length++; } }
錯誤的代碼以下:
public void delete(Magazine delNode){ MagazineNode node=new MagazineNode(delNode); MagazineNode current=list; MagazineNode behind=current; if (list==null) list=null; else if (current.magazine.toString().equals(node.toString())) current=current.next; else{ while (!current.next.magazine.toString().equals(node.toString())) { behind.next=current; current=current.next; } current=current.next; behind.next=current.next; list=behind; } }
正確的思路:
單鏈表的操做:
添加:上圖能夠看出 單向鏈表只有一個指向,原來head爲p,p指向s,添加結點只須要把p指向q,q指向s就能夠了,即:p--->q ; q--->s ; 這樣就實現了單向鏈表的添加;
刪除:原理與添加相反,若此時鏈表爲 p---> q --->s ; 若刪除q節點只須要更改p的指向就能夠了 p--->s,這樣就刪掉了;
修改以後的正確代碼以下:
public void delete(Magazine delNode) { MagazineNode front = list; MagazineNode current = front.next; if (delNode.toString().equals(front.magazine.toString())) list = front.next; else { while (!current.magazine.toString().equals(delNode.toString())) front = front.next; front.next = current.next; } }
import java.util.LinkedList; public class Sorting3 { //----------------------------------------------------------------- // Sorts the specified array of objects using the selection // sort algorithm. //----------------------------------------------------------------- public static void sortLink(LinkedList<Integer> link) { int min; int temp; for (int index = 0; index < link.size() - 1; index++) { min = index; for (int scan = index + 1; scan < link.size(); scan++) { if (link.get(scan).compareTo(link.get(min)) < 0) { min = scan; } } // Swap the values temp = link.get(min); link.set(min, link.get(index)); link.set(index, temp); } } }
測試類的代碼及運行截圖以下:
錯題1
理解:無限循環和遞歸都是類似的,它們不斷地無限重複。編譯器或運行時(JVM)都不能捕獲它們。
錯題2
錯因:忽略了輸入爲0的時候這種特殊狀況!!一樣輸入參數0,第一個return爲0,第二個則會陷入無限遞歸。
錯題3
理解:遞歸和迭代在計算上是等價的——每個均可以被另外一個取代。
。
這周我和夥伴對以前的四則運算項目進行了最後的修改和測試,夥伴編寫了一個很棒的交互程序,同時對代碼進行了格式化以及漏洞的完善,貢獻很大!!
我深深地感受到Java是一門實踐性很強的學問!Java的不少概念難以理解,並且就算理解了也不等於會靈活應用,因此對這門學科的學習仍是應該以實踐爲主!!
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 28/28 | 1/1 | 16/16 | |
第二週 | 710/738 | 1/2 | 20/36 | |
第三週 | 426/1164 | 1/3 | 16/52 | |
第四周 | 1068/2232 | 2/5 | 20/72 | |
第五週 | 604/2928 | 1/6 | 22/94 | |
第六週 | 609/3537 | 1/7 | 22/116 | |
第七週 | 599/4136 | 1/8 | 18/134 | |
第八週 | 1052/5188 | 3/11 | 20/154 | |
第九周 | 866/6054 | 1/12 | 20/174 | |
第十週 | 970/7024 | 1/13 | 20/194 |
計劃學習時間:22小時
實際學習時間:20小時
改進狀況:這部分學習的時候對概念的理解遇到了較大的麻煩,只能是經過不斷查閱各類資料去加深本身的理解,可是有的概念總感受理解得不是那麼到位!!
在查閱資料的過程當中也瞭解到實踐的重要性,要學着把更多的精力放到實踐中去,而不是一直鑽概念的牛角尖!!