鏈表,一個令人熟悉的名詞,相信很多人第一次接觸這個詞是在數據結構的書上。而且大部分這樣的書采取了C語言來作為教學代碼,很少采取C++,JAVA,C#等面向對象的語言(估計是用不上吧,而且這些面向對象的類,繼承等名詞又會讓初學者容易混淆,畢竟大家很多都是從C語言開始走上編程之路的)。
之前我有面試過一家公司,有道題目是關於用JAVA去實現鏈表。那時候我懵了,因為那時候我對java的理解也是到很淺的階段,引用什么的概念都很陌生,雖然學過數據結構,但是書上教學的是使用了指針,但是JAVA並沒有指針這個名詞啊,然后擅自用C語言的語法去答題,然后......然后就沒有然后了。
指針究竟是什么?鏈表的指針又代表了什么含義?這就是解題的具體思路。在java中,是用了引用來答題指針的功能,不過區別就是指針在指向目標地址的同時本身也占有內存,而引用就是單純的指向一塊內存。
先說說鏈表結構,通常包含表頭,節點1,節點2...節點n,其中節點又包含了數據內容和下個節點的地址。和數組結構(應該叫做順序表吧大概......)不一樣,鏈表並不用占據連續的內存,它們的區別就不多說了,相信大家都知道。
說說怎么實現吧,既然要用引用的方式來代替指針,那么就需要一個特別的類結構:需要同名的成員保存下一個節點的信息。
public class Node {
private String data;
private Node nextNode;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Node getNextNode() {
return nextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
}
該怎么使用呢?讓我們來初始化一個鏈表吧!
private Node InitNode() {
// 當前節點
Node curNode = new Node();
// 構建頭結點
Node head = new Node();
head.setData("head");
head.setNextNode(null);
// 當前節點位於頭結點
curNode = head;
// 新增第一個節點
Node n1 = new Node();
// 獲取到當前節點,使得的下一個節點設置為n1
curNode.setNextNode(n1);
n1.setData("node1");
n1.setNextNode(null);
// 當前節點位於第一個節點
curNode = n1;
// 第二個節點
Node n2 = new Node();
curNode.setNextNode(n2);
n2.setData("node2");
n2.setNextNode(null);
curNode = n2;
// 第三個節點
Node n3 = new Node();
curNode.setNextNode(n3);
n3.setData("node3");
n3.setNextNode(new Node());
curNode = n3;
// 第四個節點
Node n4 = new Node();
curNode.setNextNode(n4);
n4.setData("node4");
n4.setNextNode(new Node());
curNode = n4;
return head;
}
注意curNode的變動,使得當前節點總落在最后一個節點上,下次插入時就不需要知道前面一個節點的名字了,通過curNode就可以直接插入了。
到底成功了沒有,我們來遍歷一下。這個遍歷和C語言的很相似:
LinkMain m = new LinkMain();
Node testNode = m.InitNode();
Node iter = testNode.getNextNode();
while (null != iter) {
if (null != iter.getData()) {
System.out.println(iter.getData());
}
iter = iter.getNextNode();
}
輸出結果如下:,其中testNode是這樣的:
是不是和C語言很像呢?
----------------------------分割線---------------------------------------
OK,搞定了初始化和遍歷,讓我們來試試插入一個節點吧,需求是在某個鏈表中,第N個位置插入一個節點temp:
新增原理:對於temp節點來說
紅色代表的是之前連接,黑色的是之后應該做的。
private Node addNode(Node head, int n, Node temp) {
int i = 0;
while (null != head) {
if (i == n) {
temp.setNextNode(head.getNextNode());
head.setNextNode(temp);
return head;
} else {
head = head.getNextNode();
i++;
}
}
return head;
}
新增后再遍歷一下
// 新增一個節點
Node temp = new Node();
temp.setData("tempNode");
temp.setNextNode(null);
Node n3 = m.addNode(testNode, 2, temp);
iter = testNode.getNextNode();
while (null != iter) {
if (null != iter.getData()) {
System.out.println(iter.getData());
}
iter = iter.getNextNode();
}
那么效果如何呢?
其中testNode的內容應該是
OK,結果正確。
------------------------------------快下班了,下次來試試刪除的功能-----------------------------------------
鏈表的刪除節點功能
一開始還搞不定刪除,后來畫圖分析了下,終於解決,放上代碼。
難點是設置P,Q兩點的指向。其中q是p的下個節點。
應該先找到需要刪除的位置。
原理很簡單,就是要繞過q來連接p和后后(q后面的節點)節點。
刪除前:
刪除后:
----------------------------
哈哈解決了這個問題真是舒服。