链表
链表,别名链式存储结构或单链表,用于存储逻辑关系为 “一对一” 的数据。与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置是随机的。 其在内存中的实现过程和递归非常相似。
内存分布
先用python的代码举个例子,写一个函数主要负责把数字0加三次
def do(a):
a+=1
if(a>=3):
return
do(a)
if __name__=="__main__":
do(0)
这是一个很典型的递归调用那么其在内存中a的值的变化如下图 而对于链表的话其实它的实际的运行在内存中存储数据的时候和上图是非常相似的。事实上,在编写代码的时候就是通过递归来实现的。那么在实际的运行中数据的内存分布大概可以这样表示
方法说明
IntLinkedList实现类的方法说明
- add()添加数据,按照顺序进行添加
- print()显示所有的数据
- del()删除数据
- find() 查找数据
- updata()替换数据
- insert() 插入数据,后入,往后面插入。
私有的内部节点Node类的说明。所有的方法与功能与实现类保持一致,在命名后面加入Node后缀。例如add()与Node类对应的方法为addNode()
数据添加的实现
首先我们具有一个根节点,这个也就是我们先前那个内存图的第一个内存区域也就是根节点。 我们首先判断根节点是否存入数据,我们只需要查看root是否为null就可以。因为节点的目的是存储数据,没有new出来就没有在该节点存入数据。
(Node具有一个构造方法可以直接赋值 )
如果发现根节点存在数据,那么我们就需要创建下一个节点。那么此时调用Node类的方法。
进入addNode()方法 此时的root根节点就是我们的this,那么this.next就是当前节点(root)的下一个节点。一开始我们同样需要进行判断,是否为空。 当判断root的下一个节点this.next不为空时,那么就会再次调用this.next的addNode()方法,也就是调用第二个节点的addNode()方法。之后当调用第二个节点的方法后此时的this对应的就是第二个节点,那么此时的this.next对应的就是地三个节点,之后再进行判断是否为null,否则再继续那么它就会再次调用它的addNode()方法再进行一个循环。那么在这里就开始进入了一个迭代。并且此时你会发现当它进行数据存储时就是连续的。
数据的显示
当你知道数据的存储之后那么关于数据的显示就很简单了。 你只需要判断当前的节点是否为null就好了,如果是那么直接返回,如果不是那么显示并进入下一个节点。
数据的查找与更新
这个其实操作都是一样的只不过一个返回查询结果的真假,一个直接对数据进行修改(当找到数据后) 逻辑都是类似的这里,都是要先判断根节点下是否存在,不存在才会从第二个节点(root.next)继续,之后在这里进入迭代。 和更新的区别就是
数据的删除与插入
这个可以合在一起是因为需要对节点进行新的排序,通过对节点的排序来完成对节点的数据的删除(当不再对new出来的内存空间进行引用时,Java会对其进行垃圾回收,Java是多进程的,当Java运行时其回收器也会运行) 数据的删除
首先还是对数据进行查找是否为需要删除的 当找到之后我们就对当前的root节点替换为第二个节点(如果需要删除的是第一个节点的数据的话)
之后如果不是那么就进入下一个节点也就是再进入第二个节点,调用root.delNode() 当进入第二个节点时此时的this是root,那么第二个节点就是root.next也就是this.next,那么对应的第三个节点自然就是this.next.next(如果当需要删除的数据是第二个节点的)如果不是那么再调用第二个节点的delNode()方法查看第三个是不是,以此类推再次进入迭代!
数据插入 这个的话需要先来个记录位置的变量从0开始记录。其余的逻辑一样,区别是需要创建新的节点,之后再对其进行插入。我们目前的例子是后入,从后面插入数据,前插也是可以的。只需要搞清楚节点间的逻辑关系即可。
实现类的完整代码
class IntLinkedList{
private Node root;
private int indexnumber=0;
public void add(int data){
if(root == null){
root = new Node(data);
}
else{
root.addNode(data);
}
}
public int del(int data){
if(root==null)return -data;
else{
if(root.getData()==data){
System.out.println("数据删除完成");
root=root.next;
return data;
}
else{
root.delNode(data);
}
}
return -data;
}
public void print(){
if(root==null) {return;}
else{
System.out.println(root.data);
root.printNode();
}
}
public boolean find(int data){
if(root==null)return false;
if(root.getData()==data){
return true;
}
else{
root.findNode(data);
}
return false;}
public void updata(int oldData,int newData){
if(root==null)return;
if(root.getData()==oldData){
root.setData(newData);
}
else{
root.updataNode(oldData, newData);
}
}
public void insert(int index, int data){
if(root==null)return;
indexnumber=0;
if(index==indexnumber){
Node newNode = new Node(data);
newNode.next = root.next;
root.next = newNode;
}
else{
root.insertNode(index, data);
}
}
private class Node{
private int data;
private Node next;
public Node(int data){
this.data = data;
}
public int getData() {
return this.data;
}
public void setData(int data) {
this.data = data;
}
public void addNode(int data){
if(this.next==null){
this.next=new Node(data);
}
else{
this.next.addNode(data);
}
}
public int delNode(int data){
if(this.next==null)return -data;
if(this.next.data==data){
System.out.println("数据删除完成");
this.next = this.next.next;
}
else{
this.next.delNode(data);
}
return -data;
}
public void printNode(){
if(this.next!=null){
System.out.println(this.next.data);
this.next.printNode();
}
if(this.next==null){
return;
}
}
public boolean findNode(int data){
if(this.next==null)return false;
if(this.next!=null){
if(this.next.getData()==data){
System.out.println("find now ");
return true;
}
else{
return this.next.findNode(data);
}
}
return false;
}
public void updataNode(int oldData,int newData){
if(this.next==null)return;
if(this.next.data==oldData){
this.next.setData(newData);
}
else{
this.next.updataNode(oldData, newData);
}
}
public void insertNode(int index,int data){
indexnumber++;
if(this.next==null)return;
if(index==indexnumber){
Node newNode = new Node(data);
newNode.next = this.next.next;
this.next.next=newNode;
}
else{
this.next.insertNode(index, data);
}
}
}
}
测试
public class Linked_List_test {
public Linked_List_test(){
}
public static void main(String[] args) {
IntLinkedList ll = new IntLinkedList();
ll.add(1);
ll.add(2);
ll.add(4);
ll.add(5);
ll.add(7);
System.out.println("-------------------添加后的数据展示-----------------------");
ll.print();
System.out.println("-------------------查找结果-------------------------------");
ll.find(7);
System.out.println(ll.find(12));
System.out.println("-------------------数据更新-------------------------------");
ll.updata(7, 6);
ll.print();
System.out.println("-------------------------后入-----------------------------");
ll.insert(1, 3);
ll.print();
System.out.println("-------------------------删除数据-----------------------------");
ll.del(6);
ll.print();
}
}
总结
其实关于目前的实现的话,目前只是用一个链表实现了单向的操作,其中那个del()方法或者说那个print方法稍微改动一下就可以得到get()方法,从头部开始得到数据并且从列表中删除,这个和队列类似(Python队列的get方法类似)(java是poll方法)。至于如何得到双向的其实也很简单。最简单的思路就是搞两条链表,一个往后存储一个往前存储(往前存储是交换节点位置让初始的根节点往前移动,只移动节点的命名而不移动数据,也就是是节点移动后,把节点的数据再进行交换)(存储同一个数据)。那么一来第一条链表的第一个节点的数据与第二条链表的最后一个节点的数据对应。当从后面开始去最后一个存入的数据时直接从第二条链表的第一个节点数据开始取就好了,反之从第一个开始。
|