数据结构 二 :列表

              一。先扯点别的。今日在TX微博上一则消息传的沸沸扬扬,说是‘TX DNF游戏团队成员年终奖为48个月工资,其中甚至是客服最低年薪也达到了90万’,在群里讨论的一发不可收拾,其中既引来了多数身为其中一员的无限自豪感,也招来了无数板砖,很快,TX人力部高层也对此做了澄清,然后又是巴拉巴拉巴拉,总之最后是不了了之,对于此事我没多大感冒,不管是真是假,踏实做事才是真!

    二。再扯点别的。

    (1)在一篇技术博客上看到一些技术知识点。说:程序运行其实就是数据串的不断拷贝,比如当你写了一段代码功能是输出‘123   ,把代码文件保存至硬盘,则运行程序效果为:数据串‘123 ’先从硬盘拷贝至主存即内存,再从内存拷贝至高速缓存如L1,L2,再从高速缓存拷贝至CPU中,再从CPU拷贝至显示器。到此结束,整个过程就是一个拷贝过程,其中时间与空间消耗都花在了拷贝上,所以作为程序员可以做的就是在拷贝上做文章,即在高速缓存上进行优化。

    (2)一直觉得迅雷的技术是很牛逼牛逼的,原因是去年参加了迅雷的笔试,基本不会,很是被鄙视了一把,所以这两天也稍微看了一点比如断点下载的一些博客,至于BT下载,去年有了解了一下,貌似是一个p2p协议的应用(不是很记得了),在这里稍微说一下断点下载的思路:有服务器S,客户端C,C向S下载文件,C先生成一个文件Info以记录如需下载的文件的字节大小,是否下载完成的标志位以及已经下载到C的文件字节数,当C暂停了下载,待到下次下载,S先查看C端的Info,然后再根据根据Info的信息进行交互。思路大抵如此,不过貌似代码实现起来可没那么简单。

    三。言归正传。

    (1)列表即List,在java有ArrayList及LinkedList,而谈到这两个类,最先想到了就是他们的对比(去年为找工作这类笔试题做了不少,而且惊人的相似),即ArrayList底层实现是数组,增加或删除元素消耗大,但查询元素速度快,而LinkedList底层实现为链表,增加或删除元素消耗小,但查询元素速度慢。

    (2)对于List的了解仅限于以上,而其真正的原理尚未了解,今天的目标就是初步实现List的两个子类ArrayList和LinkedList;

    四。还是废话少说。直接贴代码:

(1)ArrayList

package com.ds.test4;

import java.util.Arrays;

public class ArrayList<E> {
	
	private int index = -1;        //索引初始为-1
	
	private int capacity = 10;     //容量初始为10
	
	E[] os = null;
	
	public ArrayList(){            //无参构造方法
		this(10);                  //容量初始为10
	}
	
	public ArrayList(int initCapacity){    //自行设置初始容量
		if(initCapacity<=0)
			throw new RuntimeException("初始容量必须大于0");
		capacity = initCapacity;
		os = (E[]) new Object[capacity];     //初始数组
		
	}
	
	public synchronized boolean add(E o){
		checkLength();
		index++;                       //索引增加
		os[index] = o;                 //赋值
		return true;
	}
	
	public synchronized E get(int where){                   //pop操作
		checkIndexAndWhere(where);
		E oo = (E) os[where];         //赋值返回值
		return oo;
	}

	public synchronized boolean set(int where,E o){         //set操作 
		checkIndexAndWhere(where);      //检查索引
		os[where] = o;                  //赋值
		return true;
	}
	
	public synchronized E remove(int where){               //remove操作
		checkIndexAndWhere(where);          //检查索引
		E oo = (E) os[where];              //赋值返回值
		E[] newOs = (E[]) new Object[capacity];
		for(int i=0;i<where;i++){
			newOs[i] = os[i];              //依次赋值
		}
		for(int i=where;i<os.length-1;i++){
			newOs[i] = os[i+1];            //依次赋值
		}
		os = newOs;
		index--;   
		return oo;
	}

	
	private void checkLength() {
		if(index>=capacity-1){        //超过容量
			capacity+=10;             //每次递增10
			E[] newOs = (E[]) new Object[capacity];
			for(int i=0;i<os.length;i++)
				newOs[i] = os[i];        //依次赋值
			os = newOs;
		}
	}
	
	private void checkIndexAndWhere(int where){      //检查索引
		if(index == -1){               //没有任何元素时抛出异常
			 throw new RuntimeException("不存在元素");  
		}
		if(where <0 || where>index){  //索引有误时抛出异常
			throw new RuntimeException("索引有误"); 
		}
	}
	
	public int size(){
		return index+1;
	}
	
	public String toString(){
		return Arrays.toString(os);
	}
	
}

 

(2)LinkedList

package com.ds.test4;

public class LinkedList<E> {
	
	private Node<E> node = null;           //头结点
	
	private int index = 0;                //索引
	
	private int nextIndex = 0;                //用来next的一个索引  
	
	private Node<E> nextNode = null;
	
	public LinkedList(){
		node = new Node<E>();             //初始化头结点
	}
	
	public synchronized boolean add(E e){   //add操作
		
		if(index == 0){
			node.addNext(new Node(e));
			index++;
		}else{
			Node<E> newNode = new Node<E>(e);
			Node<E> lastNode = getLastNode();
			lastNode.addNext(newNode);
			index++;
		}
		
		return true;
	}
	
	public E get(int where){
		E e = null;
		if(where >= index || where < 0){   //索引越界
			throw new RuntimeException("索引越界-"+where);
		}else{
			Node<E> tempNode = node;       //把头结点赋值给一个暂时头结点,以防直接操纵头结点
			for(int i = 0;i<=where;i++){
				tempNode = tempNode.getNext();
			}
			e = tempNode.getData();
			tempNode = null;               //适当考虑一下内存
		}
		return e;         //我感觉是返回E,而不是一个Node
	}
	
	public E next(){
		if(hasNext()){
			if(nextNode == null){
				nextNode = node.getNext();
				nextIndex++;
			}else{
				nextNode = nextNode.getNext();
				nextIndex++;
			}
		}else{
			throw new RuntimeException("没有元素");
		}
		return nextNode.getData();         //我感觉是返回E,而不是一个Node
	}
	
	public synchronized boolean remove(int where){
		
		Node previous = null;          //取得whrere前一个结点
		
		Node next = null;              //取得whrere后一个结点
		
		if(where >= index || where < 0){   //索引越界
			throw new RuntimeException("索引越界-"+where);
		}else{
			Node<E> tempNode = node;       //把头结点赋值给一个暂时头结点,以防直接操纵头结点
			for(int i = 0;i<=where-1;i++){     //取的where-1,即where前一结点,即previous
				tempNode = tempNode.getNext();
			}
			
			previous = tempNode;                 //取得whrere前一个结点
			Node current = previous.getNext();   //取得whrere当前结点
			next = current.getNext();            //取得whrere前一个结点
			
			previous.addNext(next);            //前一结点直接与后一结点相连
			current = null;                    //where结点 设为空
			index -- ;                         //即当前尺寸减一
		}
		
		
		return true;
	}
	
	public synchronized boolean set(int where,E e){
		
		if(where >= index || where < 0){   //索引越界
			throw new RuntimeException("索引越界-"+where);
		}else{
			Node<E> tempNode = node;       //把头结点赋值给一个暂时头结点,以防直接操纵头结点
			for(int i = 0;i<=where;i++){     
				tempNode = tempNode.getNext();
			}
			
			Node current = tempNode;
			current.setData(e);
			
		}
		
		return true;
	}
	
	public synchronized boolean insert(int where,E e){
		
		Node current = null;          //取得whrere当前结点
		
		Node next = null;              //取得whrere后一个结点
		
		if(where >= index || where < 0){   //索引越界
			throw new RuntimeException("索引越界-"+where);
		}else{
			Node<E> tempNode = node;       //把头结点赋值给一个暂时头结点,以防直接操纵头结点
			for(int i = 0;i<=where;i++){     
				tempNode = tempNode.getNext();
			}
			
			current = tempNode;           //取得whrere当前结点
			Node insertNode = new Node(e);//构造要插入的Node
			current.addNext(insertNode);  //使current的Node指向新的Node
			if(where != index){//当where等于index时将会是直接插入到链表最后,所以不存在next这个Node
				next = current.getNext();  //取得whrere后一个结点
				insertNode.addNext(next);  //使新的Node指向next的Node
			}
			
			index ++ ;                              //即当前尺寸加一
		}
		
		return true;
	}
	
	
	public boolean hasNext(){
		return (index==0?false:true) && (index>nextIndex);
	}

	private Node<E> getLastNode() {
		
		Node<E> tempNode = node;       //把头结点赋值给一个暂时头结点,以防直接操纵头结点
 		
		for(int i = 0;i<index;i++){
			tempNode = tempNode.getNext();
		}
		
		return tempNode;
	} 
	
	public int size(){
		return index;
	}
}

class Node<E>{
	
	private Node<E> next = null;
	
	private E data = null;
	
	public Node(){
	}
	
	public Node(E newData){
		data = newData;
	}
	
	public void addNext(Node<E> newNode){
		next = newNode;
	}
	
	public Node<E> getNext(){
		return next;
	}
	
	public E getData(){
		return data;
	}
	
	public void setData(E data){
		this.data = data;
	}
	
}

 

     五。sun的ArrayLIst和LinkedList源码就不贴了,在这里简单说几个问题:

    (1)发现sun的这两个类没有使用synchronized关键字,猛然想起来,原来Vector与Stack已比较少使用,原因就是涉及的多线程问题,因为考虑到安全问题,则势必会降低效率,而且也确实一般情况下不会说向列表中插入元素会有先后问题的考虑。

    (2)在这次编码中有一个循环赋值问题,即使用for循环依次赋值,而sun源码使用的是System.arraycopy,一个方法就搞定,貌似以前也了解了下深复制与浅复制的概念,这个问题在此做一标注,留待以后学习。

    六。说明:

    (1)ArrayList稍微简单一些,其中checkLength和checkIndexAndWhere这两个方法是核心,主要是涉及索引的越界判断。

    (2)LinkedList稍微复杂一些,主要还是之前对链表只是一个模糊的了解,当真正自己用代码实现起来,却也有不少麻烦事,在这说几点对链表的理解:<1>一个链表包括一个头结点

                          <2>而结点其实是对你要加入元素的一个封装(这里使用的内部类,技术上没什么说明,只是对于Node与LinkedList关系的一个反映)      

                <3>结点(Node),包括指针域(next,即下一个结点的引用)和数据域(data,即真正加入的元素)

    (3)LinkedList各方法的实现无非是围绕索引对应的结点,即previous(前一结点),next(后一结点)和current(当前结点)。

    七。总结:

    可能很多大牛或者内行看来我这些代码甚于简单而且不够严谨,不过还是那句话:权当是一个笔记,记录一个学习的过程,以后回头看来,能有所收获就够了,打住,明日继续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值