双向链表---JavaSE

数组和链表的区别:

集合框架就是将所有的数据结构,进行封装成了java自己的类,例如我们以后想实现一个顺序表,直接使用ArrayList就可以的;

主要是对数据的组织形式和描述方法是不一样的

1)顺序表的底层是一个数组,她是在逻辑上面和物理上面都是连续的

2)链表是一个有若干节点组成的一个数据结构,逻辑上面是连续的,但是在物理(内存)上面是不连续的;

3)顺序表适合查找相关的操作,因为可以通过使用下标直接获取到某个位置的元素,但是在链表中就没法通过下标来进行确定到底是哪一个位置的元素,所以链表不支持随机访问;

4)链表适合用于频繁的插入和删除操作,此时不需要像顺序表一样移动元素,顺序表插入元素,都要把元素放到后面去,顺序表删除元素,都要把元素移动到前面去;

链表的插入,只需要修改指向即可;

5)链表随用随取,要一个new一个节点,这个节点属于对象,头插,尾插时间复杂度是O(1)

但是顺序表,但是顺序表满了需要进行扩容,扩容后的空间也有可能是有些无法利用的,浪废掉了

下面我们来实现以下不带头结点的双向链表

在集合框架里面,有一个集合类,LinkedList就是用双向链表来进行表示的

我们想要实现增删查改功能

class ListNode{
    int data;
    ListNode next;//这是保存下一个节点的地址
    ListNode front;//这是保存一个前驱结点的地址
    public ListNode(int data)
    {
        this.data=data;
    }
}
class DoubleLinkedList{
ListNode head=null;
ListNode tail=null;
public void display()
{
    ListNode current=head;
    while(current!=null)
    {
        System.out.println(current.data);
        current=current.next;
    }
}
public int size()
{   int count=0;
    ListNode current=head;
    while(current!=null)
    {    count++;
        current=current.next;
    }
    return count;
}
public boolean contains(int Key)
{
  ListNode current=head;
  while(current!=null)
  {
      if(current.data==Key)
      {
          return true;
      }
      current=current.next;
  }
  return false;
}

}

 1.首先我们来进行实现头插法和尾插法

  public void addFront(int data) {
        ListNode node=new ListNode(data);
        if(head==null)
        {
            head=node;
            tail=node;
        }else{
            head.front=node;
            node.next=head;
            this.head=node;
        }

    }
    public void addLast(int data)
    {  ListNode node=new ListNode(data);
        if(head==null)
        {
            head=node;
            tail=node;
        }else{
            node.front=tail;
            tail.next=node;
            tail=node;
        }
    }

2.删除第一次出现的节点Key

当我们在单链表实现这个题的时候,我们必须要找到需要删除的关键字的前驱,假设Key=34,我们要找到关键字为Key的节点,还要找到前驱;那么在这里面我们只需要查询一个节点即可

 public void removeKey(int Key)
    {
        ListNode current=head;
        while(current!=null)
        {
            if(current.data==Key)
            {
                if(current==head)
                {
                    head=head.next;
                    head.front=null;
                     return;
                }else if(current==tail){
                   tail=tail.front;
                   tail.next=null;
                   return;
                }else{
                    current.front.next=current.next;
                    current.next.front=current.front;
                     return;
                }

            }
                current = current.next;
            

        }
    }

但是这个代码还是存在着一定的问题:

  if(current==head)
                  {
                    head=head.next;
                    head.front=null;
                     return;

                     }

1)如果我们在这里面要删除的是头结点,况且在整个代码中只有一个节点,这个双向链表中的唯一的头节点的front和next 域都是空的,如果我们此时执行这一段代码肯定就会发生空指针异常;

2)所以我们应该在这里面再次加上一个条件

3)如果我们想要删除所有Key那么就把所有的reurn去掉

             if(current==head){
                    head=head.next;
              if(head!=null){
                    head.front=null;
                 }else{
                tail=null//走到这里说明只有一个节点
                      }
                     return;
                     }

3.像双向链表中插入元素(给定一个位置)

我们先定义一个结点current指向头节点,先走index位置

1)如果是插入的下标是第一个位置,那么就采用头插法

2)如果插入的位置是最后一个位置,就采用尾插法

public void addIndex(int index,int data)
    {
        if(index<0||index>size())
        {
            throw  new UnsupportedOperationException("你所插入的下标位置不合法");
        }else{
            ListNode current=research(index);
            if(current==head)
            {
                addFront(data);
            }else if(current==tail)
            {
                addLast(data);
            }else{
                ListNode node=new ListNode(data);
                node.next=current;
                node.front=current.front;
                current.front.next=node;
                current.front=node;
            }
        }
    }

 4.清空双向链表中的所有节点

我们在这里面的核心思路是,既然要清空所有节点,那么我们终将要破坏链表的结构,所以我们可以让head一直向后走,head每走一步,我们都让head的next域和front域都变成空

public void clear()
{
    ListNode curNext=null;
    while(head!=null)
    {
        curNext=head.next;
        head.front=null;
        head.next=null;
        head=curNext;
    }
    //注意我们此时要让所有的指向链表的节点都变成空
    tail=null;
}

猜你喜欢

转载自blog.csdn.net/weixin_61518137/article/details/125233216