链表
1、单向链表
1.1、概念
- 链表是一个有序的列表
- 链表不同于数组,链表是以节点的形式存储,在物理空间上不一定连续
- 链表的每个节点的内部包含data(数据)域,指向后一个节点next(指针)域,如果是双向链表,还有一个指向前一个节点的previous (指针)域
- 链表的头结点不存储数据,只是为了指向链表的开头
1.2、对链表的操作
1.2.1、添加
//创建一个单向循环链表
class SingleLinkedList {
//设置一个头节点,头节点是固定的,无任何数据
private Node head = new Node(-1,"");
public Node getHead() {
return head;
}
/**
* 添加一个节点到链表之中(优化后的版本)
* 要根据人物的编号来插入到指定的位置(如果已经有了这个编号的人物,则添加失败,并给出提示)
*
* @param node 你要添加的节点
*/
public void adds(Node node) {
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了该节点应该插入的位置
if (temp.getNext().getId() > node.getId()) {
break;
}
//新节点的编号已经存在,给出提示信息
if (temp.getNext().getId() == node.getId()) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是添加还是给出提示信息
if (flag) {
System.out.println(node.getId() + " 该节点已经存在,不能加入!");
} else {
node.setNext(temp.getNext());
temp.setNext(node);
}
}
}
1.2.2、删除
//创建一个单向循环链表
class SingleLinkedList {
//设置一个头节点,头节点是固定的,无任何数据
private Node head = new Node(-1,"");
public Node getHead() {
return head;
}
/**
* 根据传入的 id删除该节点
*
* @param id 要删除节点的 id
*/
public void delete(int id) {
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了要删除的节点
if (temp.getNext().getId() == id) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是删除还是给出提示信息
if (flag) {
temp.setNext(temp.getNext().getNext());
} else {
System.out.println(id + " 该节点不存在,不能删除");
}
}
}
1.2.3、更新
//创建一个单向循环链表
class SingleLinkedList {
//设置一个头节点,头节点是固定的,无任何数据
private Node head = new Node(-1,"");
public Node getHead() {
return head;
}
/**
* 更新数据
*
* @param oldId 要改变的节点的 id
* @param newId 更新之后的节点的 id
*/
public void update(int oldId, int newId,String newAddress) {
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了要更新的节点
if (temp.getId() == oldId) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是删除还是给出提示信息
if (flag) {
temp.setId(newId);
temp.setAddress(newAddress);
} else {
System.out.println(oldId + " 该节点不存在,不能更新");
}
}
}
1.2.4、查找
//创建一个单向循环链表
class SingleLinkedList {
//设置一个头节点,头节点是固定的,无任何数据
private Node head = new Node(-1,"");
public Node getHead() {
return head;
}
/**
* 查找节点
*
* @param id 要查找节点的 id
* @return 返回该节点
*/
public Node find(int id){
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了要更新的节点
if (temp.getId() == id) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是删除还是给出提示信息
if (flag) {
return temp;
} else {
return null;
}
}
}
1.2.5、遍历
//创建一个单向循环链表
class SingleLinkedList {
//设置一个头节点,头节点是固定的,无任何数据
private Node head = new Node(-1,"");
public Node getHead() {
return head;
}
//遍历当前环形链表
public void showNode() {
//判断链表是否为空
if (head == null) {
System.out.println("该链表为空");
return;
}
//因为head不能动,所以使用一个辅助指来完成遍历
Node temp = head.getNext();
while (true) {
System.out.println("id为:" + temp.getId() + " 地点为:"+temp.getAddress());
//说明已经遍历完毕
if (temp.getNext() == null) {
break;
}
//temp后移
temp = temp.getNext();
}
System.out.println();
System.out.println("---------------------");
}
}
1.3、完整的源码
public class SingleLinkedListDemo {
public static void main(String[] args) {
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.adds(new Node(3,"北京"));
singleLinkedList.adds(new Node(1,"天津"));
singleLinkedList.adds(new Node(2,"上海"));
singleLinkedList.adds(new Node(4,"深圳"));
singleLinkedList.adds(new Node(0,"广东"));
singleLinkedList.showNode();
singleLinkedList.delete(1);
singleLinkedList.showNode();
singleLinkedList.update(3, 7,"南昌");
singleLinkedList.showNode();
Node node = singleLinkedList.find(3);
if (node != null){
System.out.println("查找到了id为:"+node.getId()+" 地址为:"+node.getAddress());
}else {
System.out.println("该节点不存在");
}
}
}
//创建一个单向循环链表
class SingleLinkedList {
//设置一个头节点,头节点是固定的,无任何数据
private Node head = new Node(-1,"");
public Node getHead() {
return head;
}
/**
* 添加一个节点到链表之中(优化后的版本)
* 要根据人物的编号来插入到指定的位置(如果已经有了这个编号的人物,则添加失败,并给出提示)
*
* @param node 你要添加的节点
*/
public void adds(Node node) {
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了该节点应该插入的位置
if (temp.getNext().getId() > node.getId()) {
break;
}
//新节点的编号已经存在,给出提示信息
if (temp.getNext().getId() == node.getId()) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是添加还是给出提示信息
if (flag) {
System.out.println(node.getId() + " 该节点已经存在,不能加入!");
} else {
node.setNext(temp.getNext());
temp.setNext(node);
}
}
/**
* 根据传入的 id删除该节点
*
* @param id 要删除节点的 id
*/
public void delete(int id) {
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了要删除的节点
if (temp.getNext().getId() == id) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是删除还是给出提示信息
if (flag) {
temp.setNext(temp.getNext().getNext());
} else {
System.out.println(id + " 该节点不存在,不能删除");
}
}
/**
* 更新数据
*
* @param oldId 要改变的节点的 id
* @param newId 更新之后的节点的 id
*/
public void update(int oldId, int newId,String newAddress) {
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了要更新的节点
if (temp.getId() == oldId) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是删除还是给出提示信息
if (flag) {
temp.setId(newId);
temp.setAddress(newAddress);
} else {
System.out.println(oldId + " 该节点不存在,不能更新");
}
}
/**
* 查找节点
*
* @param id 要查找节点的 id
* @return 返回该节点
*/
public Node find(int id){
//因为头节点的固定的,不能动,所以我们定义一个辅助遍历temp
Node temp = head;
//表明该节点是否存在
boolean flag = false;
while (true) {
//当该链表到了最后一个节点
if (temp.getNext() == null) {
break;
}
//表示已经找到了要更新的节点
if (temp.getId() == id) {
flag = true;
break;
}
//如果不是最后一个节点,则将temp后移
temp = temp.getNext();
}
//根据flag的值来判断是删除还是给出提示信息
if (flag) {
return temp;
} else {
return null;
}
}
//遍历当前环形链表
public void showNode() {
//判断链表是否为空
if (head == null) {
System.out.println("该链表为空");
return;
}
//因为head不能动,所以使用一个辅助指来完成遍历
Node temp = head.getNext();
while (true) {
System.out.println("id为:" + temp.getId() + " 地点为:"+temp.getAddress());
//说明已经遍历完毕
if (temp.getNext() == null) {
break;
}
//temp后移
temp = temp.getNext();
}
System.out.println("---------------------");
}
}
//创建一个节点类
class Node {
private int id;
private String address;
private Node next;
public Node() {
}
public Node(int id, String address) {
this.id = id;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
2、单向循环链表
3、双向链表
4、双向循环链表
5、小结
其实剩下的这些都是在单向链表的基础上进行进一步的优化。
如:
- 单向循环链表就是在单向链表的基础上,将链表的最后一个节点的 next指向了第一个节点,而单向链表的最后一个节点的 next是指向 null
- 双向链表就是在单向链表的基础上,在每一个节点都加上一个 previous,这个 previous指向上一个节点
- 双向循环链表是在双向链表的基础上,将链表的第一个节点的 previous指向了最后一个节点,将链表的最后一个节点的 next指向了第一个节点,而双向链表的第一个节点的 previous指向 null,双向链表的最后一个节点的 next是指向 null