雙向鍊錶結點和單向鍊錶結點的區別在於,多了乙個指向前驅的指標。當這個節點是第乙個節點時,前驅指標是乙個空指標。
單向鍊錶的結構如下圖1所示:
圖1 單向鍊錶結構圖
雙向鍊錶的結構如下圖2所示:
圖2 雙向鍊錶結構圖
顯然通過以上2個圖的對比,可以看出鍊錶兩種形式的特點。雙向鍊錶顯然我們在建立的時候需要永久維護的是first和last資訊,要是鍊錶不為空,first指向的是初始的鏈結點,last指向的是表尾的鏈結點(當只有乙個鏈結點的時候,first和last指向同乙個);初始鏈結點的prev指向null,鏈尾的鏈結點next指向null。
對雙向鍊錶的基本操作有插入、刪除和非空,其中插入有insertfirst()即在首位插入新的鏈結點、insertlast()即在末尾插入新的鏈結點、insertafter()即在某一元素值後插入新的鏈結點;同理刪除有deletefirst()、deletelast()和deletekey()。這幾個插入和刪除方法,單純的靠想象是很難的,在敲寫**的時候我們應該結合圖,看著圖示來寫邏輯,要不然繞來繞去一會兒就寫懵了。
首先鏈結點link應有的屬性如下**所示:
/**
* 鏈結點
*/public class link
}
對doublelinklist初始時有:
/**
* 雙向列表
*/public class doublelinkedlist
/***從隊尾插入鏈結點
** @param data
*/public void insertlast(int data)
//等等其他對雙向鍊錶的操作方法
}
首先是非空判斷,顯然當first==null時說明鍊錶中沒有鏈結點,**:
/**
* 鍊錶是否為空
** @return
*/public boolean isempty()
2.insertfirst()從首位插入新的鏈結點,先畫圖,圖示如下:
圖3 表頭插入
根據圖示敲**邏輯,具體如下:
/**
* 插入乙個鏈結點
** @param data
*/public void insertfirst(int data) else
first = newlink;
}
3.insertlast()從表尾插入新的鏈結點,邏輯和表頭插入比較相似,**如下:
/**
* 從隊尾插入鏈結點
** @param data
*/public void insertlast(int data) else
last = newlink;
}
4.deletefirst()刪除操作,刪除操作就是從雙向鍊錶中拿出第乙個結點,返回值型別為link:
/**
* 刪除第乙個結點
** @return
*/public link deletefirst() else
first = current.next;//無論是只有乙個結點(只有乙個的話first =null) 多個結點當前要刪除的結點的下乙個都是為第乙個
return current;
} else
}
5.deletelast()刪除表尾結點,返回值型別也是link:
/**
* 刪除最後乙個結點
** @return
*/public link deletelast() else
last = current.previous;
return current;
} else
}
以上操作相對簡單,依然是敲**的時候畫圖理解。
6.insertafter(int key,int data)在某一要素結點後插入新的結點,要處理的東西比較多,圖4中有比較好的解釋:
圖4 某結點current後插入新的結點
首先我們要找到要出入的位置,之後處理前後結點的問題,**如下:
/**
* 在指定結點後面插入新的data元素結點
** @param key 根據key找到指定結點
* @param data 要插入的新結點
*/public string insertafter(int key, int data)
}if (current == last) else
newlink.previous = current;
current.next = newlink;
return "insert succeed";
}
我設定的返回值型別是string,根據鍊錶的情況返回不同的處理資訊。
7.deletekey(int key)根據key值找到對應的結點,然後處理刪除結點之後的前後結點關係:
/**
* 根據關鍵元素值 刪除對應的鏈結點
** @param key
* @return
*/public link deletekey(int key)
}//2.說明找到key對應的鏈結點 current 刪除之
if (current == first) else if (current == last) else
//todo 以上**可以優化成以下形式 可能稍微難理解一點 假設要刪除的點是首位 current.previous就是null
// if (current == first) else
//// if (current == last) else
return current;
}
8.就是從頭到尾遍歷整個鍊錶以及從尾到頭遍歷整個鍊錶的寫法:
/**
* 從頭往後遍歷整個鍊錶
*/public void showallfromfirst()
} else
system.out.println("\n");
}/**
* 從尾到頭遍歷整個鍊錶
*/public void showallfromlast()
} else
system.out.println("\n");
}
測試類:
/**
* 雙向鍊錶測試
*/public class doublelinkedlisttest
}
輸出結果:
以上**,如有問題請大家及時指出。關於單向鍊錶請在此鏈結中檢視資料結構之鍊錶1_單鏈表及基本概念。
資料結構與演算法(4)雙向鍊錶
1.單鏈表的的缺點 1 單向鍊錶查詢的方向只能是乙個方向,而雙向鍊錶可以向前或者向後查詢 2 單向鍊錶不能自我刪除,需要考輔助節點,而雙向鍊錶則可以進行自我刪除 2.雙向鍊錶的說明 1 遍歷 和單向鍊錶一樣,只是可以向前,可以向後 2 新增 預設新增到雙向鍊錶的最後 3 修改 和單向鍊錶思路一樣 4...
演算法2 鍊錶3 雙向鍊錶
雙 向 鍊錶中有兩條方向不同的鏈,即每個結點中除next域存放後繼結點位址外,還增加乙個指向其直接前趨的指標域prior。雙向鍊錶在查詢時更方便 特別是大量資料的遍歷。注意 雙鏈表由頭指標head惟一確定的。帶頭結點的雙鏈表的某些運算變得方便。將頭結點和尾結點鏈結起來,為雙 向 迴圈鍊錶。形式描述 ...
資料結構四雙向鍊錶
雙向鍊錶也叫雙鏈表,是鍊錶的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向鍊錶中的任意乙個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。而之前的單鏈表為單向鍊錶,雙向鍊錶也就是在單鏈表的結點中增加乙個指向其前驅的pre指標。如圖 這裡介紹雙向鍊錶的常用操作 l ...