介绍
JAVA中有许多的数据结构,例如数组,队列,栈,链表等。与其他数据结构相比,链表具有增删快,充分利用碎片化空间的特点。链表是引用类型数据,它就像一个表格,包含众多节点(内部的数据通过一个个指针链所相连接)。就像下面这张图
链表都是由一个个节点构成,每个节点中包含数据与指针,指针为节点指明方向,即下一个数据或上一个数据。
分类
链表也可以分类
- 单向链表
- 双向链表
- 单向循环链表
单向链表是指链表中每个节点都只能指向下一个节点,不能指向上一个。(上面那张示意图就是单向链表)
双向链表是指链表中每个节点都可以指向上一个节点,同时也可以指向下一个节点,示意图如下
单向循环链表:一个单向链表的最后一个节点的next指针,指向开头的节点。(示意图如下)
实现链表
对于链表,我们要实现增删改查的功能。
增添数据、删除数据、修改数据、查找数据
单向链表
package DataStructure;
import java.util.Stack;
/**
* @author 23881
* 链表的增删改查
* 合并链表
* 逆序打印
*反转链表
*打印倒是第n个元素
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
SingleLinkedList list = new SingleLinkedList();
// list.add(new HeroNode(1,"peter","peterbear"));
// list.add(new HeroNode(3,"tony","hairCutter"));
System.out.println("\t增添元素");
list.AddByOrder(new HeroNode(1,"peter","peterbear"));
list.AddByOrder(new HeroNode(3,"tony","hairCutter"));
list.AddByOrder(new HeroNode(2,"jerry","printf"));
list.AddByOrder(new HeroNode(5,"jim","java"));
list.AddByOrder(new HeroNode(6,"trump","python"));
list.AddByOrder(new HeroNode(2,"jerry","printf"));
list.print();
System.out.println("\t查找元素");
list.Search(0);
System.out.println("\t更改元素");
list.Update(new HeroNode(2,"zhang","专业户"));
list.print();
System.out.println("\t删除元素");
list.Delete(2);
list.print();
System.out.println("\t此链表中节点的个数:"+list.size());
System.out.println("\t倒数第n个元素\n"+list.NodeFromLast(3));
System.out.println("\t反转后的链表");
list.ReserveNode();
list.print();
System.out.println("\t逆序打印");
list.RevPrint();
list.ReserveNode();
System.out.println("\t合并链表");
System.out.println("链表1:");
list.print();
System.out.println("链表2:");
SingleLinkedList list2 = new SingleLinkedList();
list2.AddByOrder(new HeroNode(5,"Biden","瞌睡虫"));
list2.AddByOrder(new HeroNode(8,"John","somebody"));
list2.print();
System.out.println("合并后:");
list.Combine(list2);
list.print();
}
}
class HeroNode{
public int No;
public String Name;
public String NickName;
public HeroNode next; //指向下一个节点
public HeroNode(int No, String Name, String NickName) {
this.No = No;
this.Name = Name;
this.NickName = NickName;
}
@Override
public String toString() {
return "Node[ No: "+this.No+"; Name: "+this.Name+"; NickName: "+this.NickName+" ]";
}
@Override
public boolean equals(Object obj) {
HeroNode node = (HeroNode)obj;
return node.No == this.No && node.Name.equals(node.Name) && node.NickName.equals(node.NickName);
}
}
class SingleLinkedList{
//先初始化一个头节点
public HeroNode Head = new HeroNode(0,"","");
//添加节点
//找到当前列表的最后一个节点,将最后一个节点的next指向下一个
public void add(HeroNode node) {
//head节点不能动,用一个指针指向head
HeroNode cur = Head;
//遍历链表
while(cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
//按照heronode的编号来存储数据,判断数据是否存在与存储数据
public void AddByOrder(HeroNode node) {
HeroNode cur = Head;
if(isempty()) {
add(node);
return;
}
while(cur.next != null) {
if(cur.next.No > node.No) {
node.next = cur.next;
cur.next = node;
break;
}
else if(cur.next.No == node.No ) {
System.out.printf("%s的编号%d 已存在,无法添加\n",node.Name,node.No);
break;
}
cur = cur.next;
if(cur.next == null) {
add(node);
break;
}
}
}
//对链表中数据进行反转
public void ReserveNode() {
HeroNode cur = Head.next;
HeroNode temp = new HeroNode(0,"","");
while(cur!=null) {
Head.next = cur.next;
cur.next = temp.next;
temp.next = cur;
cur = Head.next;
}
Head = temp;
//第二种
// HeroNode next =null;
// while(cur!=null) {
// next = cur.next;
// cur.next = temp.next;
// temp.next = cur;
// cur = next;
// }
// Head = temp;
}
//删除信息
public void Delete(int No) {
if(isempty()) {
System.out.println("此链表为空链表,无法删除任何元素");
return;
}
if(No == 0) {
System.out.println("无法删除头节点");
return;
}
HeroNode cur = Head;
while(cur.next != null) {
if(cur.next.No == No) {
cur.next = cur.next.next;
return;
}
cur = cur.next;
}
System.out.println("未找到匹配的信息");
}
//改变信息
public void Update(HeroNode NewNode) {
if(isempty()) {
System.out.println("链表为空");
return;
}
if(NewNode.No == 0) {
System.out.println("无法改变头节点的值");
return;
}
HeroNode cur = Head;
while(cur!=null) {
if(cur.next.No == NewNode.No) {
NewNode.next = cur.next.next;
cur.next = NewNode;
return;
}
cur = cur.next;
}
}
//查找信息
public void Search(int No) {
if(isempty()) {
System.out.println("链表为空");
return;
}
if(No == 0) {
System.out.println("此节点为头节点");
return;
}
HeroNode cur = Head;
while(cur!=null) {
if(cur.No == No) {
System.out.println("编号 "+No+":"+cur);
return;
}
cur = cur.next;
}
System.out.println("未找到匹配信息");
}
//查找单链表倒数第k个结点
public HeroNode NodeFromLast(int k) {
if(k>size()||k<=0) {
return null;
}
HeroNode cur = Head.next;
for(int i=0;i<(size()-k);i++) {
cur = cur.next;
}
return cur;
}
//判空
public boolean isempty() {
return Head.next == null;
}
//遍历打印链表
public void print() {
if(isempty()) {
System.out.println("链表为空");
return;
}
HeroNode cur = Head.next;
while (cur != null) {
System.out.println(cur);
cur = cur.next;
}
}
//从尾到头打印链表
//1.将单链表反转,然后遍历(会破坏原来的结构)
//2.利用栈,将各个节点压入到栈中,先进后出的特点,实现逆序打印的效果
public void RevPrint() {
if(isempty()) {
System.out.println("此链表为空");
return;
}
Stack<HeroNode> stack = new Stack<>();
HeroNode cur = Head.next;
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
while(stack.size()>0) {
System.out.println(stack.pop());
}
}
//获取链表节点个数
public int size() {
int count =0;
HeroNode cur = Head;
while(cur.next != null) {
cur=cur.next;
count++;
}
return count;
}
//合并链表
public void Combine(SingleLinkedList list) {
HeroNode cur = list.Head.next;
while(cur!=null) {
list.Head = cur.next;
cur.next = null;
this.AddByOrder(cur);
cur = list.Head;
}
}
}
结果
双向链表
package DataStructure;
public class DoubleLinkDemo {
public static void main(String[] args) {
DoubleLinkList list = new DoubleLinkList();
list.add(120,"CSSE");
list.add(399,"ESL");
list.add(220,"CSSE");
list.add(399,"ESL");
list.add(102,"CSSE");
list.add(221,"MA");
System.out.println("\tlist的大小:"+list.size());
System.out.println("\t正序打印");
list.print();
System.out.println("\t逆序打印");
list.Rsprint();
System.out.println("\t查找数据");
Node[] array = list.search("CSSE");
for(Node node:array) {
if(node!=null) {
System.out.println(node);
}
}
System.out.println("\t删除数据");
list.del(220);
list.print();
System.out.println("\t更改数据");
list.update(new Node(221,"MA"), new Node(113,"MA"));
list.print();
}
}
class Node{
int num;
String name;
Node pre;
Node next;
Node(int num,String name){
this.num = num;
this.name =name;
pre =null;
next=null;
}
@Override
public String toString() {
return name+" "+num;
}
@Override
public boolean equals(Object obj) {
Node node = (Node)obj;
return node.num == this.num&&node.name.equals(this.name);
}
}
class DoubleLinkList{
private Node head;
DoubleLinkList(){
head =null;
}
//判空
public boolean isempty() {
return head == null;
}
//增
public void add(int num,String name) {
Node node = new Node(num,name);
if(isempty()) {
head = node;
return;
}
Node cur = head;
while(cur.next!=null) {
if(cur.equals(node)) {
System.out.println(node+" 节点已存在,无法添加");
return;
}
cur = cur.next;
}
cur.next = node;
node.pre = cur;
}
//删
//根据编号删除数据
public void del(int num) {
Node cur = head;
//数据为空
if(isempty()) {
System.out.println("链表为空");
return;
}
//数据在开头
if(cur.num == num) {
head = cur.next;
return;
}
//数据在中间
while(cur.next!=null) {
if(cur.num == num) {
cur.pre.next = cur.next;
cur.next.pre = cur.pre;
return;
}
cur = cur.next;
}
//数据在末尾
if(cur.num == num) {
cur.pre.next= null;
return;
}
System.out.println("未找到相关数据");
}
//改,更改数据
public void update(Node Oldnode,Node Newnode) {
Node cur = head;
//数据为空
if(isempty()) {
System.out.println("链表为空");
return;
}
//数据在开头
if(cur.equals(Oldnode)) {
Newnode.next = cur.next;
cur.next.pre = Newnode;
head = Newnode;
return;
}
//数据在中间,数据在末尾
while(cur!=null) {
if(cur.equals(Oldnode)) {
Newnode.next = cur.next;
cur.pre.next = Newnode;
Newnode.pre = cur.pre;
return;
}
cur = cur.next;
}
System.out.println("未找到相关数据");
}
//查
//根据name查找数据
public Node[] search(String name) {
Node cur = head;
boolean exist = false;
Node[] array = new Node[this.size()];
int count=0;
//数据为空
if(isempty()) {
System.out.println("链表为空");
return null;
}
while(cur!=null) {
if(cur.name.equals(name)) {
array[count] = cur;
exist =true;
count++;
}
cur = cur.next;
}
if(!exist) {
System.out.println("未找到相关数据");
}
return array;
}
//list的大小
public int size() {
int count=0;
Node cur = head;
while(cur!=null) {
cur = cur.next;
count++;
}
return count;
}
//正遍历
public void print() {
Node cur = head;
if(isempty()) {
System.out.println("链表为空");
return;
}
while(cur!= null) {
System.out.println(cur);
cur = cur.next;
}
}
//逆遍历
public void Rsprint() {
Node cur = head;
if(isempty()) {
System.out.println("链表为空");
return;
}
while(cur.next!=null) {
cur = cur.next;
}
while(cur!=null) {
System.out.println(cur);
cur = cur.pre;
}
}
}
结果
单向循环链表
public class CircleLinkedListDemo {
public static void main(String[] args) {
CircleLinkedList list = new CircleLinkedList();
for(int i=0;i<5;i++) {
list.add(i);
}
System.out.println("\t添加数据");
list.print();
System.out.println("\t删除头部数据");
list.del(0);
list.print();
System.out.println("\t更改数据");
list.update(new Node(3), new Node(0));
list.print();
System.out.println("\t查找数据,是否包含此数据");
System.out.println(list.contains(3));
// System.out.println("\t删除中间数据");
// list.del(3);
// list.print();
// System.out.println("\t删除尾部数据");
// list.del(4);
// list.print();
}
}
class Node{
int num;
Node next;
Node(int num){
this.num = num;
next = null;
}
@Override
public boolean equals(Object obj) {
Node node =(Node) obj;
return node.num == this.num;
}
@Override
public String toString() {
return num+"";
}
}
class CircleLinkedList{
private Node head;
public CircleLinkedList() {
head = null;
}
//判空
public boolean isempty() {
return head == null;
}
//增
public void add(int num) {
Node node = new Node(num);
//开始为空
if(isempty()) {
head = node;
node.next = head;
return;
}
//开始不为空
Node cur = head;
while(cur.next!=head) {
if(cur.equals(node)) {
System.out.println("此数据已存在");
return;
}
cur =cur.next;
}
cur.next = node;
node.next = head;
}
//删
public void del(int num) {
Node cur = head;
//判空
if(isempty()) {
System.out.println("链表为空");
return;
}
while(cur.next!=head) {
if(cur.next.num == num) {
//数据在尾部
if(cur.next.next == head) {
cur.next = head;
return;
}
cur.next = cur.next.next;
return;
}
cur = cur.next;
}
//数据在头部,此时指针在尾部
if(cur.next.num == num) {
head = head.next;
cur.next = cur.next.next;
return;
}
System.out.println("未找到相关数据");
}
//改
public void update(Node OldNode, Node NewNode) {
Node cur = head;
if(isempty()) {
System.out.println("链表为空");
return;
}
//中间与尾部
while(cur.next != head) {
if(cur.next.equals(OldNode)) {
NewNode.next = cur.next.next;
cur.next = NewNode;
return;
}
cur =cur.next;
}
//数据在头部
if(cur.next.equals(OldNode)) {
NewNode.next = head.next;
head = NewNode;
cur.next = head;
return;
}
System.out.println("未找到相关数据");
}
//查
public boolean contains(int num) {
Node cur = head;
do{
if(cur.num == num) {
return true;
}
cur=cur.next;
}while(cur!=head) ;
return false;
}
//遍历
public void print() {
Node cur = head;
if(isempty()) {
System.out.println("链表为空");
return;
}
do{
System.out.println(cur);
cur = cur.next;
}while(cur!= head);
}
结果
总结
链表的学习比较抽象,刚开始接触会很懵,不知道哪个是哪个。多画图,多分析,对于链表的理解就会更加深刻。
参考资料
尚硅谷的数据结构:https://www.bilibili.com/video/BV1E4411H73v?p=17