1、單鏈表的創建和遍歷:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
public
class
LinkList {
public
Node head;
public
Node current;
public
void
add( int
data) {
if
(head == null )
{
head
= new
Node(data);
current
= head;
}
else
{
current.next
= new
Node(data);
current
= current.next;
}
}
public
void
print(Node node) {
if
(node == null )
{
return ;
}
current
= node;
while
(current != null )
{
System.out.println(current.data);
current
= current.next;
}
}
class
Node {
int
data;
Node
next;
public
Node( int
data) {
this .data
= data;
}
}
public
static
void
main(String[] args) {
LinkList
list = new
LinkList();
for
( int
i = 0 ;
i < 10 ;
i++) {
list.add(i);
}
list.print(list.head);
}
}
|
上方代碼中,這裏面的Node節點採用的是內部類來表示(33行)。使用內部類的最大好處是可以和外部類進行私有操作的互相訪問。
注:內部類訪問的特點是:內部類可以直接訪問外部類的成員,包括私有;外部類要訪問內部類的成員,必須先創建對象。
爲了方便添加和遍歷的操作,在LinkList類中添加一個成員變量current,用來表示當前節點的索引(03行)。
這裏面的遍歷鏈表的方法(20行)中,參數node表示從node節點開始遍歷,不一定要從head節點遍歷。
2、求單鏈表中節點的個數:
注意檢查鏈表是否爲空。時間複雜度爲O(n)。這個比較簡單。
核心代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
int
getLength(Node head) {
if
(head == null )
{
return
0 ;
}
int
length = 0 ;
Node
current = head;
while
(current != null )
{
length++;
current
= current.next;
}
return
length;
}
|
3、查找單鏈表中的倒數第k個結點:
3.1 普通思路:
先將整個鏈表從頭到尾遍歷一次,計算出鏈表的長度size,得到鏈表的長度之後,就好辦了,直接輸出第(size-k)個節點就可以了(注意鏈表爲空,k爲0,k爲1,k大於鏈表中節點個數時的情況
)。時間複雜度爲O(n),大概思路如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
int
findLastNode( int
index) {
if
(head == null )
{
return
- 1 ;
}
current
= head;
while
(current != null )
{
size++;
current
= current.next;
}
current
= head;
for
( int
i = 0 ;
i < size - index; i++) {
current
= current.next;
}
return
current.data;
}
|
如果面試官不允許你遍歷鏈表的長度,該怎麼做呢?接下來就是。
3.2 改進思路:(這種思路在其他題目中也有應用)
這裏需要聲明兩個指針:即兩個結點型的變量first和second,首先讓first和second都指向第一個結點,然後讓second結點往後挪k-1個位置,此時first和second就間隔了k-1個位置,然後整體向後移動這兩個節點,直到second節點走到最後一個結點的時候,此時first節點所指向的位置就是倒數第k個節點的位置。時間複雜度爲O(n)
代碼實現:(初版)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
Node findLastNode(Node head, int
index) {
if
(node == null )
{
return
null ;
}
Node
first = head;
Node
second = head;
for
( int
i = 0 ;
i < index; i++) {
second
= second.next;
}
while
(second != null )
{
first
= first.next;
second
= second.next;
}
return
first;
}
|
代碼實現:(最終版)(考慮k大於鏈表中結點個數時的情況時,拋出異常)
上面的代碼中,看似已經實現了功能,其實還不夠健壯:
要注意k等於0的情況;
如果k大於鏈表中節點個數時,就會報空指針異常,所以這裏需要做一下判斷。
核心代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
Node findLastNode(Node head, int
k) {
if
(k == 0
|| head == null )
{
return
null ;
}
Node
first = head;
Node
second = head;
for
( int
i = 0 ;
i < k - 1 ;
i++) {
System.out.println( "i的值是"
+ i);
second
= second.next;
if
(second == null )
{
return
null ;
}
}
while
(second.next != null )
{
first
= first.next;
second
= second.next;
}
return
first;
}
|
4、查找單鏈表中的中間結點:
同樣,面試官不允許你算出鏈表的長度,該怎麼做呢?
思路:
和上面的第2節一樣,也是設置兩個指針first和second,只不過這裏是,兩個指針同時向前走,second指針每次走兩步,first指針每次走一步,直到second指針走到最後一個結點時,此時first指針所指的結點就是中間結點。注意鏈表爲空,鏈表結點個數爲1和2的情況。時間複雜度爲O(n)。
代碼實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
Node findMidNode(Node head) {
if
(head == null )
{
return
null ;
}
Node
first = head;
Node
second = head;
while
(second != null
&& second.next != null )
{
first
= first.next;
second
= second.next.next;
}
return
first;
}
|
上方代碼中,當n爲偶數時,得到的中間結點是第n/2 + 1個結點。比如鏈表有6個節點時,得到的是第4個節點。
5、合併兩個有序的單鏈表,合併之後的鏈表依然有序:
這道題經常被各公司考察。
例如:
鏈表1:
1->2->3->4
鏈表2:
2->3->4->5
合併後:
1->2->2->3->3->4->4->5
解題思路:
挨着比較鏈表1和鏈表2。
這個類似於歸併排序。尤其要注意兩個鏈表都爲空、和其中一個爲空的情況。只需要O (1) 的空間。時間複雜度爲O (max(len1,len2))
代碼實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
public
Node mergeLinkList(Node head1, Node head2) {
if
(head1 == null
&& head2 == null )
{
return
null ;
}
if
(head1 == null )
{
return
head2;
}
if
(head2 == null )
{
return
head1;
}
Node
head;
Node
current;
if
(head1.data < head2.data) {
head
= head1;
current
= head1;
head1
= head1.next;
}
else
{
head
= head2;
current
= head2;
head2
= head2.next;
}
while
(head1 != null
&& head2 != null )
{
if
(head1.data < head2.data) {
current.next
= head1;
current
= current.next;
head1
= head1.next;
}
else
{
current.next
= head2;
current
= current.next;
head2
= head2.next;
}
}
if
(head1 != null )
{
current.next
= head1;
}
if
(head2 != null )
{
current.next
= head2;
}
return
head;
}
|
代碼測試:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
static
void
main(String[] args) {
LinkList
list1 = new
LinkList();
LinkList
list2 = new
LinkList();
for
( int
i = 0 ;
i < 4 ;
i++) {
list1.add(i);
}
for
( int
i = 3 ;
i < 8 ;
i++) {
list2.add(i);
}
LinkList
list3 = new
LinkList();
list3.head
= list3.mergeLinkList(list1.head, list2.head);
list3.print(list3.head);
}
|