資料結構與演算法-連結串列
目錄
連結串列
- 動態陣列有個明顯的缺點:可能會造成記憶體空間的大量浪費。
- 能否用多少就申請多少記憶體,連結串列就可以辦到這一點
連結串列是一種鏈式儲存的線性表,所有元素的記憶體地址不一定是連續的
連結串列的設計
介面設計
連結串列的大部分介面和動態陣列是一致的。
把不需要修改的方法寫一個父類用來繼承,然後父類(抽象類)繼承介面
介面:
package lianbiao;
public interface List<E> {
static final int ELEMENT_NOT_FOUND = -1;
/**
* 清除所有元素
*/
void clear();
/**
* 元素的數量
* @return
*/
int size();
/**
* 是否為空
* @return
*/
boolean isEmpty();
/**
* 是否包含某個元素
* @param element
* @return
*/
boolean contains(E element);
/**
* 新增元素到尾部
* @param element
*/
void add(E element);
/**
* 獲取index位置的元素
* @param index
* @return
*/
E get(int index);
/**
* 設定index位置的元素
* @param index
* @param element
* @return 原來的元素ֵ
*/
E set(int index, E element);
/**
* 在index位置插入一個元素
* @param index
* @param element
*/
void add(int index, E element);
/**
* 刪除index位置的元素
* @param index
* @return
*/
E remove(int index);
/**
* 檢視元素的索引
* @param element
* @return
*/
int indexOf(E element);
}
父類(抽象)
package lianbiao;
/**
* @Author :Ersan
* @Date 2020/10/29
* @Description
*/
public abstract class AbstractList<E> implements List<E>{
/**
* 元素的數量
*/
protected int size;
public int size(){
return size;
}
/**
* 是否為空
* @return
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 是否包含某個元素
* @param element
* @return
*/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
/**
* 新增元素到尾部
* @param element
*/
public void add(E element) {
add(size, element);
}
protected void outOfBounds(int index){
throw new IndexOutOfBoundsException("Index:"+index+", Size:"+size);
}
protected void rangeCheck(int index){
if (index<0||index>=size) {
outOfBounds(index);
}
}
protected void rangeCheckForAdd(int index){
if (index<0||index>size) {
outOfBounds(index);
}
}
}
清空元素
public void clear() {
size=0;
first=null;
}
新增元素
public void add(int index, E element) {
rangeCheckForAdd(index);
if (index==0) { //注意0的位置
first = new Node<>(element,first);
}else {
Node<E> prev = node(index - 1);
prev.next = new Node<E>(element, prev.next);
}
size++;
}
在編寫連結串列過程中,要注意邊界測試,比如 index 為 0 ,size - 0,size 時
node方法用於獲取index位置的節點
private Node<E> node(int index){
rangeCheck(index);
Node<E> node=first;
for (int i = 0; i < index; i++) {
node=node.next;
}
return node;
}
刪除元素 - remove(int index)
public E remove(int index) {
rangeCheck(index);
Node<E> node = first;
if (index==0){ //注意0的位置
first=first.next;
}else {
Node<E> prev = node(index - 1);
node=prev.next;
prev.next = node.next;
}
size--;
return node.element;
}
SingleLinkedList程式碼
package lianbiao;
/**
* @Author :Ersan
* @Date 2020/10/29
* @Description
*/
public class SingleLinkedList<E> extends AbstractList<E>{
private Node<E> first;
private static class Node<E>{
E element;
Node<E> next;
public Node(E element,Node<E> next){
this.element=element;
this.next=next;
}
}
@Override
public void clear() {
size=0;
first=null;
}
@Override
public E get(int index) {
return node(index).element;
}
@Override
public E set(int index, E element) {
Node<E> node=node(index);
E old =node.element;
node.element=element;
return old;
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
if (index==0) {
first = new Node<>(element,first);
}else {
Node<E> prev = node(index - 1);
prev.next = new Node<E>(element, prev.next);
}
size++;
}
@Override
public E remove(int index) {
rangeCheck(index);
Node<E> node = first;
if (index==0){
first=first.next;
}else {
Node<E> prev = node(index - 1);
node=prev.next;
prev.next = node.next;
}
size--;
return node.element;
}
@Override
public int indexOf(E element) {
if (element==null) {
Node<E> node =first;
for (int i = 0; i < size; i++) {
if (node.element==null) return i;
node=node.next;
}
}else {
Node<E> node =first;
for (int i = 0; i < size; i++) {
if (element.equals(node.element)) return i;
node=node.next;
}
}
return ELEMENT_NOT_FOUND;
}
private Node<E> node(int index){
rangeCheck(index);
Node<E> node=first;
for (int i = 0; i < index; i++) {
node=node.next;
}
return node;
}
@Override
public String toString() {
StringBuffer string=new StringBuffer();
string.append("size=").append(size).append(", [");
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (i!=0){
string.append(", ");
}
string.append(node.element);
node = node.next;
// if (i!=size-1){
// string.append(",");
// }
}
string.append("]");
return string.toString();
}
}
推薦一個神奇的網站
雙向連結串列
雙向連結串列可以提升連結串列的綜合效能
package lianbiao;
/**
* @Author :Ersan
* @Date 2020/10/29
* @Description
*/
public class LinkedList<E> extends AbstractList<E> {
private Node<E> first;
private Node<E> last;
private static class Node<E> {
E element;
Node<E> prev;
Node<E> next;
public Node(Node<E> prev, E element, Node<E> next) {
this.element = element;
this.next = next;
this.prev = prev;
}
}
@Override
public void clear() {
size = 0;
first = null;
last = null;
/*
* gc root :1.被棧指標指向的物件(區域性物件)
* */
}
@Override
public E get(int index) {
return node(index).element;
}
@Override
public E set(int index, E element) {
Node<E> node = node(index);
E old = node.element;
node.element = element;
return old;
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
if (index == size) { //往最後新增
Node<E> oldLast = last;
last = new Node<>(oldLast,element,null);
if (oldLast == null){ //連結串列新增的第一個元素
first = last;
}else {
oldLast.next = last;
}
}else {
Node<E> next = node(index);
Node<E> prev = next.prev;
Node<E> node = new Node<>(prev, element, next);
next.prev = node;
if (prev == null) { //index == 0
first = node;
} else {
prev.next = node;
}
}
size++;
}
@Override
public E remove(int index) {
rangeCheck(index);
Node<E> node = node(index);
Node<E> prev = node.prev;
Node<E> next = node.next;
if (prev == null){ //index == 0
first = next;
}else {
prev.next = next;
}
if (next == null){ // index == size-1
last = prev;
}else {
next.prev = prev;
}
size--;
return node.element;
}
@Override
public int indexOf(E element) {
if (element == null) {
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (node.element == null) return i;
node = node.next;
}
} else {
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (element.equals(node.element)) return i;
node = node.next;
}
}
return ELEMENT_NOT_FOUND;
}
private Node<E> node(int index) {
rangeCheck(index);
if (index < (size >> 1)) {
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
} else {
Node<E> node = last;
for (int i = size - 1; i > index; i--) {
node = node.prev;
}
return node;
}
}
public String toString(){
StringBuffer string = new StringBuffer();
string.append("size=").append(size).append(", [");
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (i != 0) {
string.append(", ");
}
string.append(node.element);
node = node.next;
// if (i!=size-1){
// string.append(",");
// }
}
string.append("]");
return string.toString();
}
}
雙向連結串列 VS 動態陣列
- 動態陣列:開闢,銷燬記憶體空間的次數相對較少,但可能造成記憶體空間的浪費(可以通過縮容解決)
- 雙向連結串列:開闢,銷燬記憶體空間次數相對較多,但不會造成記憶體空間的浪費
- 如果頻繁在尾部進行新增,刪除操作,動態陣列,雙向連結串列均可選擇
- 如果頻繁在頭部進行新增,刪除操作,建議選擇使用雙向連結串列
- 如果有頻繁的(在任意位置)新增,刪除操作,建議選擇使用雙向連結串列
- 如果有頻繁的查詢操作(隨機訪問操作),建議選擇使用動態陣列
單向迴圈連結串列
雙向迴圈連結串列
相關文章
- 資料結構與演算法-連結串列(上)資料結構演算法
- JavaScript資料結構與演算法(連結串列)JavaScript資料結構演算法
- 資料結構與演算法分析——連結串列資料結構演算法
- [ JavaScript ] 資料結構與演算法 —— 連結串列JavaScript資料結構演算法
- 資料結構與演算法-連結串列(下)資料結構演算法
- 【資料結構與演算法】——連結串列(Linked List)資料結構演算法
- 03 Javascript資料結構與演算法 之 連結串列JavaScript資料結構演算法
- 資料結構與演算法學習-連結串列下資料結構演算法
- 資料結構與演算法學習-連結串列上資料結構演算法
- python演算法與資料結構-單連結串列(38)Python演算法資料結構
- 資料結構與演算法 | 線性表 —— 連結串列資料結構演算法
- 資料結構與演算法整理總結---陣列,連結串列資料結構演算法陣列
- Redis資料結構—連結串列與字典Redis資料結構
- 資料結構-單連結串列、雙連結串列資料結構
- 資料結構與演算法——連結串列 Linked List(單連結串列、雙向連結串列、單向環形連結串列-Josephu 問題)資料結構演算法
- Redis資料結構—連結串列與字典的結構Redis資料結構
- 資料結構-連結串列資料結構
- 連結串列-資料結構資料結構
- 資料結構 - 連結串列資料結構
- 資料結構--連結串列資料結構
- 資料結構—連結串列資料結構
- 【資料結構與演算法】通俗易懂說連結串列資料結構演算法
- 演算法與資料結構基礎 - 連結串列(Linked List)演算法資料結構
- 資料結構與演算法(二)佇列、棧、連結串列資料結構演算法佇列
- 資料結構與演算法-線性表-單連結串列資料結構演算法
- python演算法與資料結構-雙向連結串列(40)Python演算法資料結構
- 資料結構與演算法 | 迴文連結串列檢測資料結構演算法
- 演算法與資料結構-連結串列((linked-list)-Java實現單向連結串列演算法資料結構Java
- Go資料結構與力扣—連結串列Go資料結構力扣
- 資料結構之「連結串列」資料結構
- JavaScript資料結構--連結串列JavaScript資料結構
- 資料結構之連結串列資料結構
- Java資料結構和演算法(一)連結串列Java資料結構演算法
- 【資料結構與演算法學習】線性表(順序表、單連結串列、雙向連結串列、迴圈連結串列)資料結構演算法
- 資料結構與演算法知識點總結(1)陣列與連結串列資料結構演算法陣列
- 結構與演算法(03):單向連結串列和雙向連結串列演算法
- 資料結構之連結串列:206. 反轉連結串列資料結構
- js資料結構--連結串列(likedList)JS資料結構