算法学习(3)-------数据结构基础之链表

链表

        1、概念
        链表是一种在物理上非顺序、非连续的物理结构,由若干的节点所组成。
        (1)单向链表
        单向链表的节点包括两部分,一部分是存放数据的data,另一部分是指向下一个节点的指针next,定义一个链表的节点:
private static class Node{
	int data;
	Node next; 
}

        链表的第一个节点称之为头节点,最后一个节点称为尾节点 ,尾节点的next指针指向空。数组访问元素是利用下标来进行访问,链表访问元素得通过指针一个一个慢慢找下去,直到找到元素。

        (2)双向链表
        双向链表与单向链表相比,多了一个指向前一个节点指针prev。
        2、链表的存储方式
        数组是在内存中占有了连续完成的存储空间,为顺序存储,链表和数组就不一样了,是随机存储的方式,就是哪有位置就去哪,在内存中分布在不同的位置,依靠指针next进行联系,所以看看链表相比数组是不是很自由,自由有自由的好处,但是也避免不了任何事物都存在两面性。
        3、链表的基本操作
        (1)查找节点
        链表查找节点起来那真是有一点点小麻烦,就像你在游乐园玩寻宝游戏一样,找到一个地方才有下一个宝藏地点的提示,不像数组那么灵活,链表需要一个指针一个指针去查,查找节点最坏的时间复杂度为O(n),因为只能按照顺序进行访问。
        (2)更新节点
        不考虑查找节点的过程,其实更新节点是异常简单的,就是把旧数据用新数据替换就好了,所以时间复杂度是O(1)。
        (3)插入节点

        链表插入节点就不像数组那么复杂还要将元素移动,链表中的元素因为实在内存空间中随机分布的,就是哪有位置就去哪,所以插入元素是很简单的。和数组一样,分为3种插入方式。
        1、尾部插入
        就是把链表最后一个节点的指针指向新插入的节点即可。
        2、中间插入
        将新插入节点的指针指向插入位置节点的指针,插入位置前置节点的next指针,指向新节点。
        3、头部插入
        将新插入节点的指针指向之前头部节点的指针,把新节点变为链表的头节点。。

        (4)删除节点

        链表删除节点就不像数组那么复杂还要将元素移动,分为3种删除方式。
        1、尾部删除
        就是把链表倒数第二个节点的指针指向新插入的节点即可。
        2、中间删除
        将要删除的节点的前置指针指向要删除节点的下一个节点即可。
        3、头部删除
        把链表的头节点设为原先头节点的next指针就可以。

插入和删除节点的时间复杂度为O(1);java中有垃圾自动回收的机制,只要没有外部的节点指向被删除的节点,那么,被删除的节点就会被自动回收。

下面是是实现链表的完整代码:

public class LinkList {
	//头节点指针
	private Node head;
	//尾节点指针
	private Node last;
	//链表实际长度
	private int size;
	/*
	 * 链表节点
	 */
	private static class Node{
		int data;
		Node next;
		Node(int data)
		{
			this.data = data;
		}
	}
	
	/**
	 * 链表插入元素
	 * @param data 插入元素
	 * @param 插入位置
	 */
	public void insert(int data,int index) throws Exception{
		if(index < 0 || index > size)
		{
			throw new IndexOutOfBoundsException("超出链表节点范围");
		}
		Node insertedNode = new Node(data);
		//空链表
		if(size == 0)
		{
			head = insertedNode;
			last = insertedNode;
		}
		else if(index == 0)
		{
			//插入头部
			insertedNode.next = head;
			head = insertedNode;
		}
		else if(index == size)
		{
			//插入尾部
			last.next = insertedNode;
			last = insertedNode;
		}
		else
		{
			//插入中间
			Node prevNode = get(index - 1);
			insertedNode.next = prevNode.next;
			prevNode.next = insertedNode;
		}
		size++;
	}
	/**
	 * 链表删除元素
	 * @param index 删除的位置
	 */
	public Node remove(int index) throws Exception{
		if(index < 0 || index >= size)
		{
			throw new IndexOutOfBoundsException("超出链表结点范围");
			
		}
		Node removeNode = null;
		if(index == 0)
		{
			removeNode = head;
			head = head.next;
		}
		else if(index == size -1)
		{
			//删除尾结点
			Node prevNode = get(index - 1);
			removeNode = prevNode.next;
			prevNode.next = null;
			last = prevNode;
		}
		else {
			//删除中间节点
			Node prevNode = get(index - 1);
			Node nextNode = prevNode.next.next;
			removeNode = prevNode.next;
			prevNode.next = nextNode;
		}
		size--;
		return removeNode;

	}
	/**
	 * 链表查找元素
	 * @param index //查找的位置
	 */
	public Node get(int index) throws Exception
	{
		if(index < 0 || index >=size)
		{
			throw new IndexOutOfBoundsException("超出链表结点范围");
			
		}
		Node temp = head;
		for(int i = 0; i < index; i++)
		{
			temp = temp.next;
		}
		return temp;
	}
	
	
	/**
	 * 输出链表
	 */
	public void output()
	{
		Node temp = head;
		while(temp != null)
		{
			System.out.println(temp.data);
			temp = temp.next;
		}
	}
	
	public static void main(String[] args) throws Exception{
		LinkList linkList = new LinkList();
		linkList.insert(3, 0);
		linkList.insert(7, 1);
		linkList.insert(9, 2);
		linkList.insert(5, 3);
		linkList.insert(6, 1);
		linkList.remove(0);
		linkList.output();
		
	}
	
	
	
}
        4、数组和链表
        数组和链表哪个好呢?当然是各有千秋。
        数组:查找O(1),更新O(1),删除和插入O(n)。
        链表:查找O(n),更新O(1),删除和插入O(1)。
所以:数组适合的是访问较多,更新和删除少的情况,而链表呢,适合的是访问较少,删除和更新较多的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值