数据结构:链表

介绍

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值