Java中自定义单链表

首先我们先了解一下什么是链表:

  链表是一种数据结构,它是一种物理存储单元上非连续,非顺序的存储单元,只是在逻辑上是连续的,链表逻辑形态和铁链相识,链表是由一系列结点组成,结点在运行时动态生成,每个结点由两部分组成及:存储数据元素的数据域,和存储下一个结点的地址的指针域,链表有易于插入,删除,存储空间灵活等优点,但是不允许随机存取。

      回归正题,我们来了解一下什么是单向链表:

单向链表是指每个结点只含有一个指针域,即构成链表的结点只有一个指向后一个结点的指针域,并且尾结点的指针为null。下面我画一个单向链表结点构成图帮助我们更好理解:

注:

 头指针:1.在线性表的链式存储结构中,头指针是指向第一个结点的指针,假如链表有头结点,则头指针就是指向链表头节点的指针
                   2.头指针具有标识作用,常用头指针冠以链表的名字
                   3.头指针是指针,不是结点,没有数据域。
                   4.无论链表是否为空,头指针均不为空。头指针是链表必需的元素。可以理解为头指针是存储在栈中的地址,用来访问链表。

 头结点:1. 头结点是为了操作方便和统一设置的,放在第一个有数据元素的结点之前,其数据域一般无意义(有些情况下也可以用来存放链表长度,用作监视哨等)
                   2.首元结点也就是第一个有数据元素的结点,是头结点后面第一个结点
                   3.头结点不是链表必须的,头结点不算在链表长度中。

因为链表在物理存储结构上不连续,只是逻辑是连续。而头指针很大一部分意义在于,我们访问链表时需要知道链表由何处开始访问,从而由头指针指向头结点(如果没有则指向第一个有数据元素的结点),每个结点的指针依次指向下一个结点,这样可以通过指针和给定下标找到需要的结点。所以说头指针是必须的元素,没有头指针无法访问链表。

 好了,单链表粗略的介绍完了,现在我们开始自己定义写一个单链表,我们以int数据类型为列:

1.我们知道链表都是由一个个结点组成;所以首先我们需要一个结点类,以定义数据类型和指针域,结点类代码如下:

public class Node {
	 //数据
	int data;
	//下一个节点
	Node next;
	Node before;
	//创建一个无参数构造方法,用于初始化
	public Node(){
		
	}
	//创建一个有参数构造方法,便于给结点传数据
   public Node(int data){
	   this.data=data;
	   
   }
}

 2,接口类,我们在接口类中定义我们想要这个链表实现什么功能的方法;如删除,添加,修改插入等方法,代码如下

public interface LinkList {
	
	
	//存储
	public void add(int e);
	//插入
	public void insert(int e,int index);
	//删除
	public void delete(int index);
	//获取
	public int get(int index);
	
	public void set(int data);
	//修改
	public void updata(int index,int newValue);
	//获取元素个数
	public int getSize();
	
	public Node getNext();
	public void setNext(Node next);


}

 3.链表类,我们在链表类中继承接口类并且重写链表类中所有的方法,定义链表的3个重要属性:头结点,尾节点,链表长度(元素个数)

首先我们分析一下链表删除功能的方法,要实现删除功能我们只需要找到我们要删除的结点,我们通过下标遍历找到这个结点的上一个结点,断开上一个结点和要删除结点的指针连接,让上一个结点的指针指向要删除结点的下一个结点,置空要删除结点的数据元素域和指针域,如图所示:

 代码如下:

	public void delete(int index) {
		check(index);
		// 下标为index的节点
		Node node1 = head.next;
		if (index != 0) {
			for (int i = 0; i < index; i++) {
				node1 = node1.next;

			}
			// 下标为index-1的节点,index的前一个节点
			Node node2 = head.next;
			for (int i = 0; i < index - 1; i++) {
				node2 = node2.next;
			}
			if (index != size - 1) {// 如果不是最后一个节点
				Node node3 = node1.next;// index的下一个节点
				node2.next = node3;// 将前一个节点指向后一个节点
				node1.next = null;// 断开前一个节点和index节点
			} else {
				node1.next = null;// 断开前一个节点和index节点
			}
			node1 = null;
			// node1.next=null;
		} else {
			Node node6 = head.next;
			Node node7 = node6.next;
			head.next = null;
			head.next = node7;
			node6.next = null;

		}
		size--;
	}

 插入方法:创建一个要插入的结点。找到要插入结点位置index和前一结点位置index-1 。若要插入点是最后一个,直接将原最后结点指向新加入结点。若不是,置空index-1的结点指针,再设置指向要加入结点,设置要加入结点指针指向原index结点。

 代码如下:

public void insert(int e, int index) {
		check(index);
		Node node1 = head.next;
		for (int i = 0; i < index; i++) {
			node1 = node1.next;// 找到index节点
		}
		Node node2 = new Node(e);
		if (index == 0) {// 如果插在最前面
			head.next = null;// 断开头结点和第一个节点
			head.next = node2;// 头结点指向第一个节点
			node2.next = node1;// 新节点指向原来第一节点
		} else {
			Node node3 = head.next;
			for (int i = 0; i < index - 1; i++) {
				node3 = node3.next;
			}
			node3.next = null;
			node3.next = node2;
			node2.next = node1;

		}
		size++;
	}

 添加结点的方法:代码如下

public void add(int e) {

		// 创建一个新节点
		// next=new Node(obj);
		// if(size==0){
		// // root.
		// }
		Node node = new Node(e);
		// 尾节点的下一个节点,设为新节点
		tail.next = node;
		// 修改尾节点变为新节点
		tail = node;
		// 修改元素个数
		size++;

	}

其他方法不再细讲,留给读者,下面给出我的整个链表类的代码:

import java.util.ArrayList;

public class Jiedian implements LinkList {
	// Node root=new Node();
	Node head = new Node();// 头节点
	// 尾节点
	Node tail;
	// 元素个数
	// Node next;
	int size;
	private int data;

	public Jiedian() {
		// 初始化头结点和尾节点
		head = new Node();
		tail = head;
		size = 0;
	}

	public void check(int index) {

		if (index < 0 || index > size) {
			throw new IndexOutOfBoundsException("参数不对");
		}

	}

	public void add(int e) {

		// 创建一个新节点
		// next=new Node(obj);
		// if(size==0){
		// // root.
		// }
		Node node = new Node(e);
		// 尾节点的下一个节点,设为新节点
		tail.next = node;
		// 修改尾节点变为新节点
		tail = node;
		// 修改元素个数
		size++;

	}

	public void insert(int e, int index) {
		check(index);
		Node node1 = head.next;
		for (int i = 0; i < index; i++) {
			node1 = node1.next;// 找到index节点
		}
		Node node2 = new Node(e);
		if (index == 0) {// 如果插在最前面
			head.next = null;// 断开头结点和第一个节点
			head.next = node2;// 头结点指向第一个节点
			node2.next = node1;// 新节点指向原来第一节点
		} else {
			Node node3 = head.next;
			for (int i = 0; i < index - 1; i++) {
				node3 = node3.next;
			}
			node3.next = null;
			node3.next = node2;
			node2.next = node1;

		}
		size++;
	}

	public void delete(int index) {
		check(index);
		// 下标为index的节点
		Node node1 = head.next;
		if (index != 0) {
			for (int i = 0; i < index; i++) {
				node1 = node1.next;

			}
			// 下标为index-1的节点,index的前一个节点
			Node node2 = head.next;
			for (int i = 0; i < index - 1; i++) {
				node2 = node2.next;
			}
			if (index != size - 1) {// 如果不是最后一个节点
				Node node3 = node1.next;// index的下一个节点
				node2.next = node3;// 将前一个节点指向后一个节点
				node1.next = null;// 断开前一个节点和index节点
			} else {
				node1.next = null;// 断开前一个节点和index节点
			}
			node1 = null;
			// node1.next=null;
		} else {
			Node node6 = head.next;
			Node node7 = node6.next;
			head.next = null;
			head.next = node7;
			node6.next = null;

		}
		size--;
	}

	public int get(int index) {

		Node node = head.next;
		// 从头节点开始,依次向后查找
		for (int i = 0; i < index; i++) {
			node = node.next;

		}
		return node.data;
	}

	public void updata(int index, int e) {

		Node node1 = head.next;
		for (int i = 0; i < index; i++) {

			node1 = node1.next;

		}

		node1.data = e;

	}

	public int getSize() {
		// TODO Auto-generated method stub
		return size;
	}

	public static void main(String[] args) {
		// 创建链表
		Jiedian kk = new Jiedian();
		// 添加元素
		kk.add(55);
		kk.add(89);
		kk.add(18);
		kk.add(92);
		kk.add(562);
		kk.add(782);
		kk.add(45);
		kk.delete(4);
		kk.insert(666, 3);
		kk.updata(4, 5555);
		for (int i = 0; i < kk.getSize(); i++) {
			int e = kk.get(i);
			System.out.println("第" + i + "个元素是:" + e);
		}

	}

写到这就收笔了,也请各位技术大佬多多指正,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值