什么是链表,手写一个LinkedList链表
不涉及泛型,存储的数据类型为int类型
1 认识链表
链表是一种数据结构,是线性表的一种,由一个个节点组成,节点中包括数据域和指针域
相比我们用的最多的一种数据结构——数组,数组可以存储一个固定大小的相同类型元素的顺序集合,所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
两种结构均可实现数据的顺序存储,但是
-
数组元素在栈区,链表元素在堆区
-
数组在内存中连续,链表一般来说不连续,随机分配
-
数组插入或者删除元素需要的时间长,而链表则只需要找到并增加或者删除
-
数组大小是定义时分配好了,链表可以随着你的添加不断扩大。
2本篇涉及到的节点
对于一个集合来说,一般只需要存储size、first和last。而节点中需要prev,key,next。
于是我们的节点类和集合的基本属性和方法就确定下来了
public class IntegerNode {
public Integer key;
public IntegerNode prev;
public IntegerNode next;
public IntegerNode(IntegerNode prev,Integer key,IntegerNode next) {
this.key=key;
this.prev=prev;
this.next=next;
}
@Override
public String toString() {
return "IntegerNode{" +
"key=" + key +
'}';
}
}
public class FQLinkedList {
IntegerNode first;
IntegerNode last;
int size = 0;
public FQLinkedList() {
}
}
3需要的方法
写的方法主要有以下这些
1 add方法
/**
*添加一个节点到末尾
* @param integer:插入链表的节点中的值
* @return
*/
public boolean add(Integer integer){
IntegerNode integerNode=new IntegerNode(last,integer,null);
if(first==null){
first=integerNode;
last=first;
}
else {
last.next=integerNode;
last = integerNode;
}
size++;
return true;
}
/**
* 加到指定节点之前
* @param integer:插入的值
* @param integerNode:指定下标的节点
*/
public void addBefore(int integer, IntegerNode integerNode){
IntegerNode integerNode1 = new IntegerNode(integerNode.prev,integer,integerNode);
if(integerNode.prev!=null) integerNode.prev.next = integerNode1;
else first = integerNode1;
integerNode.prev=integerNode1;
}
有了以上两个方法一般的add都能实现
2clear方法
/**
*
* 清空链表
*/
public void clear(){
for(IntegerNode x=first;x!=null;){
IntegerNode c=x.next;
x.prev=null;
x.key=null;
x.next=null;
x=c;
}
size=0;
}
/**
* 该方法也能清空链表
*/
public void clear1(){
first=last=null;
size=0;
}
在LinkedList源码中,关于clear方法是使用第一种方法,但是为什么不能使用第二种呢?
3contains方法
/**
* 返回对应元素所在链表的位置
* @param x:要查询的元素
* @return
*/
public int indexOf(int x){
int index=0;
for(IntegerNode c=first;c!=null;c=c.next){
if(c.key==x)return index;
index++;
}
return -1;
}
/**
* 判断链表是否包含该元素
* @param x:指定一个元素
* @return
*/
public boolean contains(int x){
if(indexOf(x)!=-1)return true;
return false;
}
4get方法
/**
* 获得指定下标节点的值
* @param index:指定一个下标
* @return
*/
public int get(int index){
return integerNode(index).key;
}
5关于栈和队列
/**
* 将指定元素插入链表末尾
* @param x:指定元素
* @return
*/
public boolean offer(int x){
return add(x);
}
/**
*返回第一个节点的值并移除它
* @return
*/
public int poll(){
IntegerNode integerNode=first;
first=first.next;
first.prev=null;
size--;
return integerNode.key;
}
/**
*从这个列表所表示的堆栈中弹出一个元素。
*/
public int pop(){
IntegerNode integerNode=last;
last=last.prev;
size--;
return integerNode.key;
}
/**
* 将一个元素推到由该列表表示的堆栈上。
* @param x:指定元素
*/
public void push(int x){
addFirst(x);
}
6替换,set方法
/**
* 将此列表中指定位置的元素替换为指定的元素。
* @param index:指定下标
* @param id:要更换的值
* @return 返回更换的元素
*/
public int set(int index,int id) {
IntegerNode x = first;
for (int i = 0; i < index; i++) x = x.next;
x.key = id;
return id;
}
/**
* 更换指定下标的元素
* @param id:要更换的值
* @return 返回更换的元素
*/
public int set(int index,int id) {
IntegerNode x = first;
for (int i = 0; i < index; i++) x = x.next;
x.key = id;
return id;
}
后记
其实对于写一个链表来说,我们最好先构思出父类要怎么写,从父类中抽象出各种集合所需要的共有的方法,其次再去构造子类集合