鏈表(單鏈表)
**定義:**單鏈表是一種鏈式存取的數據結構,用一組地址任意的存儲單元存放線性表中的數據元素。
鏈表中的數據是以結點來表示的,
每個結點的構成:元素(數據元素的映象) + 指針(指示後繼元素存儲位置),元素就是存儲數據的存儲單元,
指針就是連接每個結點的地址數據
本篇文章只是記錄一下學習鏈表和使用代碼實現,文章有寫的不好或不對的可以指出,初次寫稿,多多見諒
我們開始吧:
1.首先我們需要理解鏈表的數據結構的組成吧,如下圖
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/2020051921011868.jpg#pic_center)
鏈表中的每一個節點都包含兩個部分: **data(數據域)和next(下一個節點指向)**
2. 鏈表的優缺點
優點:
1. 刪除和修改快(相對於數組數據結構來說)
2. 鏈表存儲是分散的空間地址(數組是連續性的存儲地址,需要-一開始指定存儲大小)
3. 擴展性好,
缺點:
1.查詢慢,因爲查詢需要從頭開始遍歷查詢(不能按索引位置查詢)
3.代碼實現如下
//定義一個鏈表類 基礎類
class HearNode {
public Integer code;
public String name;
public String nickName;//以上是data數據域的屬性
public HearNode next; //指針域
public HearNode(Integer code, String name, String nickName) {
this.code = code;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HearNode{" +
"code=" + code +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
再定義一個實現鏈表的curd操作方法類
//封裝方法
class LianBiaoDemo {
//初始化鏈表 定義頭結點
HearNode head = new HearNode(null, "", "");
/**
* 1 首先需要找到鏈表最後一個節點 將該節點next指向插入的節點數據即可
*
* @param hearNode
*/
public void addList(HearNode hearNode) {
HearNode hea = head;
//如果hea 的下一個節點爲null 則表示已經到了尾節點
while (hea != null) {
if (hea.next == null) {
break;
}
hea = hea.next;
}
hea.next = hearNode;
}
/**
* 獲取頭節點信心
*/
public HearNode getFirst() {
if (head.next == null) {
System.out.println("該鏈表是空的 ~~~");
}
System.out.println(head.next);
return head.next;
}
/**
* 獲取尾節點信息
*/
public void getLast() {
if (head.next == null) {
System.out.println("該鏈表是空的 ~~~");
}
HearNode last = head;
while (true) {
if (last.next == null) {
break;
}
last = last.next;
}
System.out.println(last);
}
/**
* 獲取鏈表的有效節點數
*
* @return
*/
public int getCount() {
//首先做鏈表非空判斷
if (head.next == null) {
System.out.println("此鏈表爲空的 ~~~");
return 0;
}
HearNode hea = head;
//獲取鏈表的長度
int i = 0;
while (hea.next != null) {
hea = hea.next;
i++;
}
return i;
}
/**
* 鏈表反轉
*/
public void revserNodeList() {
//先判斷節點個數是否爲等於1或者爲空
if (head.next == null || head.next.next == null) {
return;
}
//定義一個輔助變量指針 來遍歷原始的鏈表
HearNode hea = head.next;
//定義一個新的鏈表 只想當前節點【hea】的下一個節點
HearNode next = null;
//新的鏈表的頭節點信息
HearNode newHead = new HearNode(null, "", "");
//遍歷原來的鏈表,每遍歷一個節點,就將其取出,並放在新的鏈表的newHead 的最前端
while (hea != null) {
//記錄鏈表指針 記錄信息
next = hea.next;
//新鏈表的頭節點指向取出的數據信息
hea.next = newHead.next;
//獲取到最新的節點信息放到變量鏈表的頭節點
newHead.next = hea;
//循環遍歷
hea = next;
}
// 將鏈表的頭節點指向變量節點的頭節點 head.next -> newHead.next
head.next = newHead.next;
}
/**
* 獲取鏈表中的第N個節點信息
* 1. 首先需要獲取到鏈表的總的長度 需要先遍歷一邊
* 2.定義一個變量接收要獲取的第幾個節點信息 index
* 3.得到長度之後 從鏈表的第一個開始遍歷(總長度 - index)個 就可以得到
* 4.如果找到就返回 沒有找到就返回空
*
* @return
*/
public HearNode getIndex(int index) {
//首先做鏈表非空判斷
if (head.next == null) {
System.out.println("此鏈表爲空的 ~~~");
return null;
}
//獲取鏈表的長度
int i = getCount();
//然後判斷 鏈表長度與獲取指定index作比較 如果爲空或者index爲負數 則直接返回
if (i < index || index <= 0) {
System.out.println("該index超出鏈表的長度");
return null;
}
HearNode hea = head.next;
for (int j = 0; j < i - index; j++) {
hea = hea.next;
}
return hea;
}
/**
* 從尾打印鏈表數據
* @param
*/
public void StackInfo(){
//判斷鏈表是否爲空
if (head.next ==null){
return;
}
//獲取頭節點信息
HearNode hea=head;
Stack stack=new Stack();
while (hea.next !=null){
hea=hea.next;
//進棧
stack.push(hea);
}
while (!stack.empty()){
// 出棧
System.out.println("打印出來"+stack.pop());
}
}
/**
* 鏈表插入時按照大小排序
* 1 我們採用頭結點的形式進行添加數據 所以需要定義一個頭結點信息 但是這個頭結點不做修改
* 2. 定義一個輔助變量 flag 來判斷 循環接節點與插入的節點大小比對 如果當前節點的下一個節點比插入節點大 則將插入的節點放置到當前節點下個節點前即可
*
* @param hearNode
*/
public void sortList(HearNode hearNode) {
//定義一個頭結點
HearNode hea = head;
boolean flag = false;
//hea不爲空則循環繼續
while (hea != null) {
//如果hea的下一個節點爲null 則表示到達最後一個節點
if (hea.next == null) {
break;
}
//這裏也可以做一個判斷 如果節點相同則不讓它添加
//判斷 如果當前節點code 大於當前code 則將當前的數據放在當前節點之前
//我們刪除一個節點 需要找到刪除節點的前一個節點
if (hea.next.code > hearNode.code) {
flag = true;
break;
}
hea = hea.next;
}
//如果flag爲ture 則將當前插入的數據放到當前節點之後
if (flag) {
hearNode.next = hea.next;
hea.next = hearNode;
} else {
hea.next = hearNode;
}
}
/**
* 刪除節點信息
*
* @param code
*/
public void delteNode(int code) {
//判斷當前鏈表是否爲空
if (head.next == null) {
System.out.println("當前鏈表爲空~~");
}
//定義一個變量
HearNode hea = head;
//定義一個標誌位 記錄查詢到刪除的code
boolean flag = false;
while (hea != null) {
if (hea.next == null) {
break;
}
//如果當前節點的code等於刪除的code 則表示找到了記錄信息
if (hea.next.code == code) {
flag = true;
break;
}
hea = hea.next;//後移遍歷
}
//判斷標誌位是否爲ture
if (flag) {
//表示找到了刪除的數據信息
hea.next = hea.next.next;
} else {
System.out.println("未找到刪除的節點信息");
}
}
/**
* 查詢連表數據信息
*/
public void selectList() {
if (head.next == null) {
System.out.println("當前鏈表爲空~~");
return;
}
HearNode hea = head.next;
while (hea != null) {
System.out.println(hea);
hea = hea.next;
}
}
/**
* 修改節點信息
* 1 首先需要循環遍歷 去匹配找到需要修改的節點信息
*
* @param updateCode
*/
public void updateCode(int code, HearNode updateCode) {
//判斷頭結點的下一個是否爲空,如果爲空則直接返回
if (head.next == null) {
return;
}
HearNode hea = head;
//定義一個輔助變量 記錄是否找到修改信息的數據
boolean flag = false;
while (hea != null) {
if (hea.next == null) {
break;
}
//判斷當前節點的下一個數據的code是否修改的數據信息
if (hea.next.code == code) {
flag = true;
break;
}
hea = hea.next;//循環遍歷
}
//如果爲ture則表示找到了
if (flag) {
hea.next.name = updateCode.name;
hea.next.nickName = updateCode.nickName;
} else {
System.out.println("未找到需要修改的信息數據");
}
}
最後我們再對方法進行測試,如下:
public class LianBiao {
public static void main(String[] args) {
LianBiaoDemo lianBiaoDemo = new LianBiaoDemo();
//進行數據添加操作
HearNode node = new HearNode(9, "wang", "~~~");
HearNode node01 = new HearNode(15, "li", "~~~");
HearNode node02 = new HearNode(3, "tang", "~~~");
HearNode node04 = new HearNode(6, "tang01", "~~~");
HearNode node05 = new HearNode(6, "tang02", "~~~");
lianBiaoDemo.sortList(node01);
lianBiaoDemo.sortList(node);
lianBiaoDemo.sortList(node02);
lianBiaoDemo.sortList(node05);
lianBiaoDemo.sortList(node04);
//查詢方法
lianBiaoDemo.selectList();
//刪除
System.out.println("刪除錢");
lianBiaoDemo.delteNode(9);
lianBiaoDemo.delteNode(15);
lianBiaoDemo.selectList();
//修改
System.out.println("修改前的數據信息~~~~");
HearNode newHearNode = new HearNode(3, "修改", "修改成功");
lianBiaoDemo.updateCode(3, newHearNode);
lianBiaoDemo.selectList();
//1.獲取頭節點信息
System.out.println("頭節點信息爲====》");
lianBiaoDemo.getFirst();
//2.獲取尾節點信息
System.out.println("尾節點信息======》");
lianBiaoDemo.getLast();
//3.求單鏈表的有效節點數
System.out.println("鏈表的有效長度:" + lianBiaoDemo.getCount());
//4.獲取鏈表的倒數第n個節點信息
System.out.println("獲取指定indexe鏈表的數據===》" + lianBiaoDemo.getIndex(5));
//5.單鏈表的反轉 例如 123 ==》 321 123456====》654321 類似與這種反轉
/**
* 反轉的思路如下
* 1.方法有很多 可以利用鏈表 +隊列 來實現反轉操作
* 這個方法還是用鏈表來實現 不過需要藉助一個鏈表來進行
* 2. 定義一個新的鏈表
*/
System.out.println("反轉鏈表~~");
lianBiaoDemo.revserNodeList();
lianBiaoDemo.selectList();
//6從尾到頭打印單鏈表 (要求方式: 1. 反向遍歷 2. stack棧)
/**
* 可以利用棧的先進後出進行實現
*/
System.out.println("反轉");
lianBiaoDemo.StackInfo();
}
}