Java資料結構與演算法筆記——單向連結串列和雙端連結串列
阿新 • • 發佈:2021-02-05
技術標籤:資料結構與演算法
文章目錄
連結串列
連結串列是一種常見的基礎資料結構,是一種線性表,但是連結串列不會按線性的順序儲存資料,而是在每個節點裡存到下一個節點的指標。
優點:
使用連結串列結構可以克服陣列需要預先知道資料大小的缺點,連結串列結構可以充分地利用計算機記憶體空間,實現靈活的記憶體動態管理。
缺點:
連結串列失去了陣列隨機讀取的優點(沒有下標),同時連結串列由於增加了節點的指標域,空間開銷比較大。
單向連結串列
單向連結串列簡介
單向連結串列是連結串列中結構最簡單的。
一個單鏈表的節點(Node)分為兩個部分,第一部分儲存或者顯示關於節點的資訊,另一個部分儲存下一個節點的地址。
最後一個節點儲存地址的部分指向空值。連結串列有一個頭結點。
查詢:
從第一個節點開始遍歷
刪除:
刪除節點,把上一個節點的指標指向下一節點(速度比陣列快)
插入:
在頭部插入
java實現單向連結串列
package link;
public class SingleLinkTest {
public static void main(String[] args) {
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.addHead('A');
singleLinkedList.addHead('B');
singleLinkedList.addHead('C');
singleLinkedList.addHead('D');
//列印連結串列
singleLinkedList.display();
System.out.println(singleLinkedList.delete('A'));
singleLinkedList. display();
System.out.println(singleLinkedList.isEmpty());
System.out.println(singleLinkedList.deleteHead());
}
}
//封裝單向連結串列的類
class SingleLinkedList{
private int size; //連結串列的節點數
private Node head; // head是頭結點的指標,引入了一個新型別,node
//構造方法
public SingleLinkedList(){
size = 0;
head = null;
}
//向連結串列中新增節點(新增到頭部)
public Object addHead(Object data){
Node newNode = new Node(data);
if(size == 0){
//空連結串列
head = newNode;
}else {
//非空連結串列
newNode.next = head;
head = newNode;
}
size ++;
return newNode;
}
//連結串列刪除頭結點,預設連結串列中是有節點的
public Object deleteHead(){
Object obj = head.data;
head = head.next;
size--;
return obj;
}
//查詢指定資料所對應的節點物件
public Node find(Object data){
Node curent = head;
int tmpSize = size;
while (tmpSize > 0){
if (data.equals(curent.data)){
//找到了物件
return curent;
}else {
curent = curent.next;
}
tmpSize--;
}
return null; //如果找不到
}
//判斷連結串列是不是空連結串列
public boolean isEmpty(){
return size==0;
}
//刪除指定節點,刪除成功返回true,失敗返回false
public boolean delete(Object value){
if(isEmpty()){
//空表
return false;
}
//不是空表
Node current = head;
Node previous = head;//上一個變數
while (!value.equals(current.data)){
if (current.next == null){
//已經掃描到了尾結點,且沒找到資料
return false;
}else{
//還沒到尾結點
previous = current;
current = current.next;
}
}
// 迴圈終止了,還會繼續執行下面的語句,證明已經找到了要找的節點
//刪除找到的節點
if(current == head){
head = head.next;
size --;
}else{
previous.next = current.next;
size --;
}
return true;
}
//遍歷輸出所有node資訊
public void display(){
if (size>0){
//不是空的
Node current = head;
int tmpSize = size;
if (tmpSize == 1){
System.out.println("[" + head.data + "]");
return; // 結束掉方法
}
while (tmpSize>0){
if (current == head){
System.out.print("[" + current.data + "->");
}else if(current.next == null){
//最後一個節點
System.out.print(current.data + "]");
}else {
System.out.print(current.data + "->");
}
tmpSize --;
current = current.next;
}
System.out.println();//輸出一個換行符
}else {
//空列表
System.out.println("[]");
}
}
//定義一個私有類
private class Node{
private Object data; //封裝在節點裡的資料
private Node next; //指標,指向下一個節點
//構造方法
public Node(Object data){
this.data = data;
}
@Override
public String toString() {
return "Node [data=" + data + ", next=" + next + "]";
}
}
}
雙端連結串列
雙端連結串列簡介
對於單向連結串列,我們如果想在尾部新增一個節點,那麼必須從頭部一直遍歷到尾部,找到尾結點,然後在尾結點後面插入一個節點。
這樣操作很慢,如果我們在設計連結串列的時候多個對尾結點的引用,那麼會簡單很多。
java實現雙端連結串列
package link;
public class DoubleLinkedListTest {
public static void main(String[] args) {
DoubleLinkedList link = new DoubleLinkedList();
link.addHead(1);
link.addHead(0);
link.addTail(2);
link.addTail(3);
link.addTail(2);
link.display();
link.delete(2);
link.display();
System.out.println(link.deleteHead());
link.display();
while(!link.isEmpty()){
System.out.println(link.deleteTail());
}
}
}
class DoubleLinkedList{
private int size; //連結串列的節點數
private Node head; // head是頭結點的指標,引入了一個新型別,node
private Node tail; //指向尾結點的指標
//構造方法
public DoubleLinkedList(){
size = 0;
head = null;
tail = null;
}
//向連結串列中新增節點(新增到頭部)
public Object addHead(Object data){
Node newNode = new Node(data);
if(size == 0){
//空連結串列
head = newNode;
tail = newNode;
}else {
//非空連結串列
newNode.next = head;
head = newNode;
}
size ++;
return newNode;
}
//新增尾結點
public Object addTail(Object data){
Node newNode = new Node(data);
if(size == 0) {
//空連結串列
head = newNode;
tail = newNode;
}else {
tail.next = newNode;
tail = newNode;
}
size ++;
return newNode;
}
//連結串列刪除頭結點
public Object deleteHead(){
Object obj = null;
if(size == 0){
//空連結串列
return obj;
}else if(size == 1){
//連結串列中只有一個節點
obj = head.data;
head = null;
tail = null;
size --;
}else{
obj = head.data;
head =head.next;
size --;
}
return obj;
}
//刪除尾部節點
public Object deleteTail(){
Object obj = null;
if(size == 0){
//空連結串列
return obj;
}else if(size == 1) {
//連結串列中只有一個節點
obj = tail.data;
head = null;
tail = null;
size --;
}else {
obj = tail.data;
// int tmp = 1;
Node tmpNode = head;
// while (tmp<size-1){
// tmpNode = tmpNode.next;
// tmp ++;
// }
while (tmpNode.next != tail){
tmpNode = tmpNode.next;
}
tail = tmpNode;
tail.next = null;
size --;
}
return obj;
}
//判斷連結串列是不是空連結串列
public boolean isEmpty(){
return size==0;
}
//刪除指定節點,刪除成功返回true,失敗返回false
public boolean delete(Object value){
if(isEmpty()){
//空表
return false;
}
//不是空表
Node current = head;
Node previous = head;//上一個變數
while (!value.equals(current.data)){
if (current.next == null){
//已經掃描到了尾結點,且沒找到資料
return false;
}else{
//還沒到尾結點
previous = current;
current = current.next;
}
}
// 迴圈終止了,還會繼續執行下面的語句,證明已經找到了要找的節點
//刪除找到的節點
if(size == 1){
head = null;
tail = null;
}else if(current == head){
head = head.next;
}else if(current == tail){
previous.next = null;
tail = previous;
}else {
previous.next = current.next;
}
size --;
return true;
}
//遍歷輸出所有node資訊
public void display(){
if (size>0){
//不是空的
Node current = head;
int tmpSize = size;
if (tmpSize == 1){
System.out.println("[" + head.data + "]");
return; // 結束掉方法
}
while (tmpSize>0){
if (current == head){
System.out.print("[" + current.data + "->");
}else if(current.next == null){
//最後一個節點
System.out.print(current.data + "]");
}else {
System.out.print(current.data + "->");
}
tmpSize --;
current = current.next;
}
System.out.println();//輸出一個換行符
}else {
//空列表
System.out.println("[]");
}
}
//獲取節點個數
public int getSize(){
return size;
}
//定義一個私有類
private class Node{
private Object data; //封裝在節點裡的資料
private Node next; //指標,指向下一個節點
//構造方法
public Node(Object data){
this.data = data;
}
@Override
public String toString() {
return "Node [data=" + data + ", next=" + next + "]";
}
}
}
基於雙端連結串列實現佇列
佇列:隊尾插入,隊頭刪除。先進先出。
package link;
public class QueueDoubleLinkedListTest {
public static void main(String[] args) {
QueueDoubleLinkedList queueDoubleLinkedList = new QueueDoubleLinkedList();
queueDoubleLinkedList.insert(1);
queueDoubleLinkedList.insert(2);
queueDoubleLinkedList.insert(3);
queueDoubleLinkedList.insert(4);
queueDoubleLinkedList.display();
System.out.println(queueDoubleLinkedList.delete());
queueDoubleLinkedList.display();
System.out.println(queueDoubleLinkedList.isEmpty());
System.out.println(queueDoubleLinkedList.getSize());
}
}
class QueueDoubleLinkedList{
private DoubleLinkedList doubleLinkedList;
public QueueDoubleLinkedList(){
doubleLinkedList = new DoubleLinkedList();
}
//插入(連結串列尾部插入)
public void insert(Object data){
doubleLinkedList.addTail(data);
}
//刪除(連結串列頭部刪除)
public Object delete(){
return doubleLinkedList.deleteHead();
}
//是否為空
public boolean isEmpty(){
return doubleLinkedList.isEmpty();
}
//獲取佇列元素個數
public int getSize(){
return doubleLinkedList.getSize();
}
//顯示佇列元素
public void display(){
doubleLinkedList.display();
}
}