資料結構(二)--- 線性錶鏈表(單鏈表)java實現方式
阿新 • • 發佈:2018-11-10
線性表的鏈式儲存結構:所有元素不考慮相鄰位置,哪有空位置就到那裡,而只是讓每個元素知道它下一個元素的位置在那裡,這樣,我們可以在第一個元素時,就知道第二個元素的位置(記憶體地址),而找到它;在第二個元素時,再找到第三個元素的位置,這樣所有的元素就可以通過遍歷而找到。
連結串列中的第一個結點的儲存位置叫做頭指標,最後一個結點的指標為空
在單鏈表的第一個結點前附設一個結點,稱為頭結點
單鏈表的插入和刪除
刪除操作:
插入元素e的結點為s,只需要將s插入到結點P 和p.next之間就行。
s.next=p.next p.next=s
如果將p.next=s;再 s.next=p.next; 第一句p.next會覆蓋s的地址,就等於s.next=s,真正擁有ai+1資料元素的結點就沒上級了,要注意。不能寫反。
刪除操作:
刪除ai元素時,只需要將ai+1指向ai-1就可以。
單鏈表LinkList
package likend;
/**
* Created by yxf on 2018/3/24.
* 線性表 單鏈表
*/
public class LinkList<T> {
private Node header;//儲存頭結點
private int size; //連結串列長度
public class Node<T> {
private T data; //資料
private Node next; //指向下一個節點的引用
public Node() {
}
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
public LinkList() {
}
/**
* 在頭結點插入
* 連結串列中第一個結點儲存位置叫做頭指標 頭節點只儲存頭指標
* 所以這是插入的是第一個節點
*
* @param element
* @return
*/
public boolean addHead(T element) {
//如果第一個連結串列為空
if (header == null) {
header = new Node(element, null);
} else {
Node newNode = new Node(element, null);
Node temp = header;
newNode.next = temp; //將新插入的節點的next指向頭節點的下一個節點
header = newNode; //將新插入的節點指向頭結點的下一個節點 連結串列就連結上了
}
size++;
return true;
}
/**
* 在尾部插入
*
* @param element
* @return
*/
public boolean add(T element) {
//如果第一個連結串列為空
if (header == null) {
header = new Node(element, null);
} /*else {
int length = getSize();
Node currentNode = getNodeByIndex(length-1);
Node newNode = new Node(element, null);
currentNode.next = newNode;
}*/ else {
Node currentNode = header;
while (currentNode.next != null) {
currentNode = currentNode.next; //找到新增結點的上一個結點
}
Node newNode = new Node(element, null);
currentNode.next = newNode;
}
size++;
return true;
}
/**
* 獲取指定位置結點
*
* @param index
* @return
*/
public Node getNodeByIndex(int index) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("獲取位置超過連結串列長度範圍");
}
Node current = header; //從連結串列第一個遍歷 因為頭結點是指標
for (int i = 0; i <= size && current != null; i++, current = current.next) {
if (i == index)
return current;
}
return null;
}
/**
* 獲取指定索引處的元素
*
* @param index
* @return
*/
public T getElement(int index) {
return (T) getNodeByIndex(index).data;
}
public int getIndex(T element) {
Node current = header;
for (int i = 0; i < size && current != null; i++, current = current.next) {
if (current.data.equals(element))
return i;
}
return -1;
}
/**
* 在指定位置插入元素
*
* @param index
* @param element
* @return
*/
public boolean insert(int index, T element) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("插入位置超出連結串列範圍");
/* //如果第一個連結串列為空
if (header == null) {
add(element);
} else {
if (index == 0) {
addHead(element);
} else {
//獲取插入位置的前一個結點
Node preNode = getNodeByIndex(index - 1);
preNode.next = new Node(element, preNode.next);
size++;
}
}*/
if (index == 0) {
addHead(element);
} else {
Node preNode = header;
for (int i = 0; i < index - 1; i++) {
preNode = preNode.next; //獲得插入結點的前驅結點
}
Node newNode = new Node(element, null);
newNode.next = preNode.next;
preNode.next = newNode;
size++;
}
return true;
}
/**
* 刪除元素
*
* @param index
* @return
*/
public T delete(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("刪除位置超出連結串列範圍");
/* Node delNode = null;
//刪除的是第一個節點
if (index == 0) {
delNode = header;
header = header.next;
} else {
Node preNode = getNodeByIndex(index - 1); //獲取刪除結點的上一個結點
delNode = preNode.next; //獲取要刪除的結點
preNode.next = delNode.next; //將要刪除結點的下一個結點賦值給刪除結點的上一個結點
}*/
Node currentNode = header;
if (index == 0) {
header = header.next;
currentNode.next=null;
} else {
Node currentNodeBefore = null;
for (int i = 0; i < index; i++) {
currentNodeBefore = currentNode; //前置結點
currentNode = currentNode.next; //要刪除的當前結點
}
currentNodeBefore.next = currentNode.next;
}
size--;
return (T) currentNode.data;
}
/**
* 獲取指定元素的前驅
*
* @param currentElem
* @return
*/
public T priorElement(T currentElem) {
int index = getIndex(currentElem);
if (index == -1)
return null;
else {
if (index == 0) {
return null;
} else {
return (T) getNodeByIndex(index - 1).data;
}
}
}
/**
* 獲取指定元素的後驅
*
* @param currentElem
* @return
*/
public T nextElement(T currentElem) {
int index = getIndex(currentElem);
if (index == -1)
return null;
else {
if (index == size - 1) {
return null;
} else {
return (T) getNodeByIndex(index + 1).data;
}
}
}
//刪除最後一個元素
public T remove() {
return delete(size - 1);
}
/**
* 獲取連結串列大小
*
* @return
*/
public int getSize() {
return size;
}
//檢查連結串列是否為空
public boolean isEmpty() {
return size == 0;
}
public void clear() {
header = null;
size = 0;
}
@Override
public String toString() {
if (isEmpty())
return "[]";
else {
StringBuilder sb = new StringBuilder("[");
for (Node current = header; current != null; current = current.next)
sb.append(current.data + "->").toString();
int len = sb.length();
return sb.delete(len - 2, len).append("]").toString();
}
}
}
測試 LinkListTest
package likend;
/**
* Created by yxf on 2018/3/25.
*/
public class LinkListTest {
public static void main(String[] args) {
LinkList ls = new LinkList();
ls.add(2);
ls.add(4);
ls.add(5);
ls.addHead(1);
System.out.println("新增元素後的連結串列為: "+ls);
ls.insert(3,3);
System.out.println("在連結串列位置3插入元素: "+ls);
ls.delete(3);
System.out.println("在連結串列位置3刪除元素: "+ls);
ls.remove();
System.out.println("刪除連結串列中的一個元素: "+ls);
System.out.println("獲得連結串列位置為2處的元素: "+ ls.getElement(2));
System.out.println("獲取元素2的前驅元素: "+ls.priorElement(2));
System.out.println("獲取元素2的後驅元素: "+ls.nextElement(2));
ls.clear();
System.out.println(ls);
}
}
測試結果
新增元素後的連結串列為: [1->2->4->5]
在連結串列位置3插入元素: [1->2->4->3->5]
在連結串列位置3刪除元素: [1->2->4->5]
刪除連結串列中的一個元素: [1->2->4]
獲得連結串列位置為2處的元素: 4
獲取元素2的前驅元素: 1
獲取元素2的後驅元素: 4
[]
Process finished with exit code 0