单链表
单链表:n个结点链接成一个链表,就是线性表的链式存储,因为此链表的每个结点只包含一个指针域,所以叫做单链表。
结点由存储数据元素的数据域和存储指针的指针域组成
我们把单链表的第一个结点叫做头指针,之后的每一个结点就是上一个结点的后继结点指向的位置。为了方便表示,一般在第一个结点之前设置一个结点,称为头结点,头结点的数据域可以不存储任何信息,也可以存储线性表的长度等附加信息,指针域指向第一个结点的指针。
头指针和头结点的异同
头指针:
- 头指针是指链表只想第一个结点的指针,若链表有头结点,则是指向头结点的指针
- 无论链表是否为空,头指针均不为空,头指针是链表的必要元素。
头结点:
- 头结点是为了方便操作设置的,放在第一个元素之前,数据域一般无意义。
- 便于插入和删除第一个结点,操作与其他结点操作一样
- 头结点不一定是链表必要元素
结点代码
public class Node {
int value; //数据域
Node next; //指针域
public Node(){
}
public Node(int value){
this.value = value;
next = null;
}
}
单链表的插入和删除
插入:时间复杂度为O(1)
如图:只需要将q指向p的下一个结点,将q设为p的下一个结点,就完成了插入.
q.next = p.next p.next = q;
注意:只能先连右边,否则会找不到p.next结点;或者将p.next结点先保存起来,就可以随便链接。
删除:时间复杂度为O(1)
如图:只需将p的下一个结点设为p的下下一个结点。
p.next = p.next.next
查找:时间复杂度为O(n)
- 首先声明一个指针保存头结点,判断他的下一个结点是否为空,不为空,判断是否是要查找的值,不是则判断下一个结点。
单链表代码实现
public class MyLinkedList {
private Node head; //头节点
public MyLinkedList() {
head = new Node(0);
}
//插入
public void addHead(int value){
Node n = new Node(value);
n.next = head.next;
head.next = n;
}
public void addLast(int value){
Node n = new Node(value);
Node temp = head;
while (temp.next != null){
temp = temp.next;
}
temp.next = n;
}
public void add(int i,int value){
Node n = new Node(value);
Node temp = head;
while(i-- > 0){
if (temp.next == null){
throw new NullPointerException();
}
temp = temp.next;
}
n.next = temp.next;
temp.next = n;
}
//删除最后一个节点
public int deleteLast(){
Node temp = head;
while (temp.next.next != null){
temp = temp.next;
}
if (temp.next != null){
int oldValue = temp.next.value;
return oldValue;
}else{
throw new NullPointerException( );
}
}
//删除第一个出现的value值
public boolean delete(int value){
Node temp = head;
boolean flag = false;
while (temp.next != null){
if (temp.next.value == value){
temp.next.value = 0; //置空防止内存泄漏
temp.next = temp.next.next;
flag = true;
break;
}else{
temp = temp.next;
}
}
return flag;
}
//获取第i个位置的元素
//倒数第k个元素距离最后一个元素的距离是k,那么我将temp和n的距离设为k,当n的到达最后一个结点,temp就是倒数第k个结点。
public int get(int i){
Node temp = head;
while(i-- > 0){
if (temp.next == null){
throw new NullPointerException();
}
temp = temp.next;
}
return temp.next.value;
}
//获取倒数第i个位置的元素
public int getLastK(int K){
Node temp = head.next;
Node n = head;
for (int j=0;j<K;j++){
n = n.next;
if (n == null)
throw new NullPointerException();
}
while (n.next != null){
temp = temp.next;
n = n.next;
}
return temp.value;
}
//修改第i个位置的元素
public int set(int i,int value){
Node temp = head;
while(i-- > 0){
if (temp.next == null){
throw new NullPointerException();
}
temp = temp.next;
}
int oldValue = temp.next.value;
temp.next.value = value;
return oldValue;
}
//链表长度
public int size(){
int size = 0;
Node temp = head;
while (temp.next != null){
size++;
temp = temp.next;
}
return size;
}
//链表逆置 从链表的第二个结点开始采用头插法重新插入结点。
public void reverse(){
if (head.next == null){
return ;
}
Node temp = head.next.next;
head.next.next = null; //将第一个结点和第二个结点断开
Node n; //保存第二个结点到最后一个结点的头结点
while (temp != null){
n = temp.next;
temp.next = head.next;
head.next = temp;
temp = n;
}
}
//输出
public void show(){
Node temp = head;
while(temp.next != null){
System.out.println(temp.next.value);
temp = temp.next;
}
}
}
测试代码:
public static void main(String[] args) {
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addHead(2);
myLinkedList.addHead(1);
myLinkedList.add(2,3);
//myLinkedList.reverse();
myLinkedList.show();
System.out.println(myLinkedList.getLastK(1));
//System.out.println(myLinkedList.size());
/*System.out.println(myLinkedList.get(1));
myLinkedList.set(1,4);
myLinkedList.show();*/
// myLinkedList.show();
// System.out.println(myLinkedList.delete(1));
/*myLinkedList.addLast(3);
myLinkedList.addLast(4);
myLinkedList.show();*/
}