单向链表的节点由两部分组成,一个是值,一个是下一个节点的引用(指针)。
其数据在内存中存储是不连续的,它存储的数据分散在内存中。
单向链表向外暴露的只有一个头节点(Head),对链表的所有操作,都是直接或者间接地通过其头节点来进行的。
添加元素时,在链表头部添加,效率最高。在链表的中间 或尾部添加,效率很低。
以下是根据链表的原理进行的简单的实现,不一定严谨和健壮
java实现的代码如下:
public class MyLinkedList<T> implements Iterable<T> {
public int size;
//头结点
public Node firstNode;
class Node{
//节点的值
private T data;
//节点的后驱节点
private Node next;
public Node(T data) {
super();
this.data = data;
}
@Override
public String toString() {
return "Node [data=" + data + ", next=" + next + "]";
}
}
/**
* 自定义迭代器
*/
private class MyListIterator implements Iterator<T> {
private int current = 0;
private Node currNode = head;
@Override
public boolean hasNext() {
return current<size;
}
@Override
public T next() {
try {
current++;
T t = currNode.data;
if(currNode.next != null){
currNode = currNode.next;
}
return t;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
/**
* 根据下标获取节点,下标从开始
* @param index:获取下标为index的节点;index-1:获取下标为index的前驱节点;index+1:获取下标为index的后驱节点
* @return
* @throws Exception
*/
public Node getNode(int index) throws Exception {
if(index<0||index>size-1){
throw new Exception("请传入合法的下标");
}
int location=0;
Node temp=firstNode;
while(temp.next!=null&&location!=index){
temp=temp.next;
location++;
}
return temp;
}
/**
* 根据节点查找下标,如果有多个相同的节点,返回查找到的第一个
*/
public int getIndex (T t){
if(firstNode!=null){
//如果第头节点就是要查找的节点,直接返回下标
if(firstNode.data.equals(t)){
return 0;
}
Node temp=firstNode;
int location=0;
//这种判断方式不能判断链表的头节点,所以头结点额外判断
while(temp.next!=null){
temp=temp.next;
location++;
if(temp.data.equals(t)){
return location;
}
}
}
return -1;
}
/**
* 添加新节点,直接添加在链表的头部,然后该节点作为链表的新头结点
* @param t
*/
public void add(T t){
Node newNode=new Node(t);
if(firstNode==null){
firstNode=newNode;
size=1;
}else{
newNode.next=firstNode;
firstNode=newNode;
size++;
}
}
/**
* 找到原链表的最后一个节点,然后将新节点加到该节点后面
* 效率低,不推荐
* @param t
*/
public void addNode(T t){
Node newNode=new Node(t);
if(firstNode==null){
firstNode=newNode;
size=1;
}else{
Node temp=firstNode;
while(temp.next!=null){
temp=temp.next;
}
temp.next=newNode;
size++;
}
}
/**
* 通过下标添加节点(效率很低)
* 1,根据下标查找当前节点,2,新节点的下一个节点指向当前节点的下一个节点,3,当前节点的下一个节指向新节点
* @param t 值
* @param index 下标
* @throws Exception
*/
public void addNode(T t,int index) throws Exception{
Node newNode=new Node(t);
if(firstNode==null){
firstNode=newNode;
size=1;
}else{
Node temp=getNode(index);
newNode.next=temp.next;
temp.next=newNode;
size++;
}
}
/**
* 1.找到下标对应的节点,将其后驱节点的值和next复制到该节点,可以认为该节点被清除了
* 2.如果该下标对应的节点没有后驱节点(最后一个节点),那么查找该下标节点的前驱节点,将该前驱节点的next设为null,也可以认为该节点被清除。
* @param index
* @throws Exception
*/
public void deleteNode(int index) throws Exception{
if(firstNode==null){
size=0;
return;
}else{
Node temp=getNode(index);
if(temp.next!=null){
temp.data=temp.next.data;
temp.next=temp.next.next;
size--;
}else{
//查找改下标对应的前驱节点
Node preNode=getNode(index-1);
//将前驱节点的next设为null
preNode.next=null;
size--;
System.err.println("preNode是:"+preNode);
}
}
}
/**
* 根据值删除对应的节点
* @param t
* @throws Exception
*/
public void deleteNode(T t) throws Exception{
int index=getIndex(t);
if(index!=-1){
deleteNode(index);
}
}
/**
* 更新某一个下标对应节点的值
* @param index 下标
* @param newValue 新值
* @throws Exception
*/
public void update(int index,T newValue) throws Exception{
if(firstNode!=null){
Node node= getNode(index);
node.data=newValue;
}
}
/**
* 先根据旧节点的值找到对应的下标,同(int index,T newValue)
* @param oldValue 旧节点值
* @param newValue 新节点值
* @throws Exception
*/
public void update(T oldValue,T newValue) throws Exception{
if(firstNode!=null){
int index=getIndex(oldValue);
if(index!=-1){
Node node= getNode(index);
node.data=newValue;
}
}
}
/**
* 链表反转
* 原理:然后让当前节点指向上一个节点(反转前当前节点指向的是下一个节点),循环
* @return
*/
public Node reverse(){
Node pre=null;
Node cur=firstNode;
while(cur!=null){
//临时变量记录当前的下一个节点,后面的循环就是遍历这个临时变量节点
Node temp=cur.next;
//当前节点指向上一个节点
cur.next=pre;
pre=cur;
//临时变量的值付赋给当前节点
cur=temp;
}
this.firstNode=pre;
return pre;
}
@Override
public Iterator<T> iterator() {
// TODO Auto-generated method stub
return new MyListIterator();
}
public static void main(String[] arrgs) throws Exception {
MyLinkedList<String> myList=new MyLinkedList<String>();
myList.add("11");
myList.add("22");
myList.add("33");
myList.add("44");
myList.add("55");
/*myList.addNode("11");
myList.addNode("22");
myList.addNode("33");
myList.addNode("44");
myList.addNode("11.5", 3);
myList.addNode("10.5", myList.size-1);*/
for (String string : myList) {
System.err.println(string);
}
//myList.deleteNode(myList.size-1);
//myList.deleteNode("11");
/* myList.update("11.5", "2222");
System.err.println("大小是"+myList.size+myList.firstNode);
System.err.println("下标是:"+myList.getIndex("11"));
myList.reverse();
System.err.println("大小是"+myList.size+myList.firstNode);*/
}
}
运行结果:
55
44
33
22
11