鏈表結構
什麼是鏈表結構
數據部分,保存的是該節點的實際數據。
地址部分,保存的是下一個結點的地址。
鏈表結構就是由許多這種結點構成的。在進行鏈表操作時,首先需要定義一個“引用頭”變量(一般以head表示),該引用變量指向鏈表結構的第一個結點,第一個結點的地址部分又指向第二個結點…… 直到最後一個結點。最後一個節點不再指向其他結點,稱爲“表尾”,一般在表尾的地址部分放一個空地址null,鏈表到此結束。
由於採用了引用來只是下一個數據的地址。因此在鏈表結構中,邏輯上相鄰的結點在內存中不一定相鄰,邏輯相鄰關係通過地址部分的引用來實現相鄰關係。
鏈表結構帶來的最大好處就是結點之間不要求連續存放,因此在保存大量數據時不要求分配連續的存儲空間。用戶可以用new函數動態分配結點的存儲空間,當刪除某個結點時,給該結點賦null,釋放其佔用的內存空間。
當然鏈表也有缺點,那就是浪費存儲空間。因此,對於每個結點數據,都要額外保存有個引用變量。但是,在某些時候,鏈表結構所帶來的好處還是大於其缺點。
對於鏈表的訪問,要衝表頭head開始找到第一個結點,再從第一個結點找到第二個結點……這樣逐個比較一直找到需要的結點爲止,而不能像順序表那樣進行隨機訪問。
鏈式存儲不僅可以用來表示線性表,而且可用來表示各種非線性的數據結構。
實例類
public class DATA2 {
private String key;
private String name;
private int age;
//
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
鏈表
// 鏈表
public class CLType {
DATA2 nodeData = new DATA2();
CLType nexNode;
// 追加結點
// 在鏈表末尾加一個結點。表尾結點的地址部分保存的是空地址null,
// 此時需將其設置爲新增結點的地址(既遠表位結點地址指向新增結點),
// 然後將新增結點的地址部分設置爲null,既新增結點設置成尾。
CLType ClAddEnd(CLType head, DATA2 nodeData){
CLType node,htemp;
if((node=new CLType())==null){
System.out.println("申請內存失敗!");
return null;
}else {
node.nodeData = nodeData; // 保存數據
node.nexNode = null; // 設置結點引用爲空,表尾
if(head == null){ // 頭引用
head = node;
return head;
}
htemp = head;
while (htemp.nexNode!=null){ // 查找鏈表表尾
htemp = htemp.nexNode;
}
htemp.nexNode = node;
return head;
}
}
// 插入頭結點
// 插入頭結點即在鏈表首部添加結點的過程。插入頭結點的過程,插入頭結點分爲三步
/**
* 1 分配內存空間,保存新增結點。
* 2 使新增結點指向head頭指向的結點。
* 3 使頭引用head指向新增結點。
*/
CLType CLAddFirst(CLType head,DATA2 nodeData){
CLType node;
if((node = new CLType())==null){
System.out.printf("申請內存失敗!");
return null;
}
else {
node.nexNode = head.nexNode; // 指向頭引用所指的結點
node.nodeData = nodeData; // 保存數據
head.nexNode = node; // 頭引用指向新結點
return head;
}
}
// 查找結點
//查找結點就是在鏈表結構中查找需要的元素。對於鏈表結構來說,一般可以通過關鍵字進行查詢。
CLType CLFindNode(CLType head,String key) { // 查找結點
CLType htemp;
htemp = head;
while (htemp != null){
if (htemp.nodeData.getKey().equals(key)){
return htemp;
}
htemp = htemp.nexNode;
}
return null;
}
// 插入結點
// 插入結點既在鏈表中間部分的指定位置增加一個節點。
/**
* 1 分配內存空間,保存新增的結點。
* 2 找到插入的邏輯位置,也就是位於哪兩個節點之間。
* 3 修改插入位置結點的引用,使其指向新增結點,而使新增結點指向原插入位置所指向的結點。
*/
CLType CLInsertNode(CLType head,String findkey,DATA2 nodeData){
CLType node,nodetemp;
if((node = new CLType())== null){
System.out.println("申請內存失敗!");
return null;
}
node.nodeData = nodeData;
nodetemp=CLFindNode(head,findkey);
if(nodetemp!=null){
node.nexNode = nodetemp.nexNode;
nodetemp.nexNode = node;
}else{
System.out.printf("未找到指定位置!");
}
return head;
}
// 刪除結點
// 刪除結點就是將鏈表中的某個結點數據刪除。
/**
* 1 查找需要刪除的結點。
* 2 使前一結點指向當前結點的下一結點。
* 3 刪除結點。
*/
int CLDeleteNode(CLType head,String key){
CLType node,htemp;
htemp = head;
node = head;
while (htemp!=null){
if(htemp.nodeData.getKey().compareTo(key)==0){
node.nexNode=htemp.nexNode;
htemp = null;
return 1;
}else {
node = htemp;
htemp = htemp.nexNode;
}
}
return 0;
}
// 計算鏈表長度
// 計算鏈表長度即統計鏈表結構中結點的數量。在順序表中比較方便,但是在鏈表中。鏈表結構在物理上不是連續存儲的。因此計算鏈表長度稍複雜。
int GLLength(CLType head){
CLType htemp;
int Len = 0;
htemp = head;
while (htemp!=null){
Len++;
htemp = htemp.nexNode;
}
return Len;
}
}