数据结构基础知识(一)——链表

                              数据结构基础知识(一)——链表_第1张图片

1.  链表

链表作为最基本的数据结构,存储特点:可以用任意一组存储单元来存储单链表中的数据元素(即存储单元可以是不连续的),其中一个结点(数据域,地址域),数据域:数据元素,地址域:链表元素的前驱或后继元素的地址。一个线性链表必须使用一个头指针记住元素a0的节点地址。

时间复杂度:1)O(1):isEmpty;

              O(n):toString();size();get(i);set(i);insert(i,x);remove(i);

search(key);remove(key);

2)插入或删除后继点的时间是O(1),插入前驱点或删除自己的时间是O(n)

3)插入或删除的时间花在查询上。

2.  如何从链表中删除重复数据

   publicclass myLinkedList {

   Nodehead =null;//链表头的引用

   /**

    * 插入数据内容:新节点

    * @param d

    */

   publicvoid addNode(String d){

       NodenewNode=newNode(d);

       if(head==null){

           head=newNode;

           return;

       }

       Nodetmp=head;

       while(tmp.next!=null){

           tmp=tmp.next;

       }

       tmp.next=newNode;

   }

   publicvoid printList(){

       Nodetmp=head;

       while(tmp!=null){

           System.out.print(tmp.data+" ");

           tmp=tmp.next;

       }

   }

   /**

    * 删除重复的字符元素

    * @param head

    */

   publicvoid deleteDuplecate(){

       Hashtabletable=newHashtable();

       Nodetmp=head;

       Nodepre=null;

       while(tmp!=null){

           if(table.containsKey(tmp.data))

               pre.next=tmp.next;

           else{

               table.put(tmp.data, 1);

               pre=tmp;

           }

           tmp=tmp.next;

       }

   }

   publicstatic void main(String[] args) {

       myLinkedListlist=newmyLinkedList();

       list.addNode("a");

       list.addNode("e");

       list.addNode("e");

       list.addNode("f");

       list.addNode("a");

       list.addNode("g");

       list.printList();

       System.out.println(" ");

       list.deleteDuplecate();

       list.printList();

   }

}

这种删除重复元素的方法优点是时间复杂度较低,但是缺点是在遍历过程中需要额外的存储空间来保存已遍历过的值。

另外还用一种方法,不需要额外的存储空间,但是时间复杂度较高。主要思路:对链表进行双重循环遍历,外循环正常遍历链表,假设外循环当前遍历的节点为cur,内循环从cur开始遍历,若碰到与cur所指向节点值相同,则删除这个重复节点。

publicvoid deleteDuplecate2(){

       Nodep=head;

       while(p!=null){

           Nodeq=p;

           while(q.next!=null){

               if(p.data==q.next.data){

                   q.next=q.next.next;

               }else

                   q=q.next;

           }

           p=p.next;

       }

   }

3.       如何找出单链表中的倒数第k个元素

1)  改进后的一种方法:从头至尾的方向从链表中的某个元素开始,遍历k个元素后刚好达到链表尾,那个该元素就是要找的倒数第k个元素,此方法要对同一批元素进行反复多次的遍历.算法复杂度为O(kn),效率太低。

2)  另一种高效的方式:从头到尾进行遍历查表,设置两个指针,让其中一个指针比另一个指针先前移k-1步,然后两个指针同时向前遍历。知道先行的指针值为NULL是,另一个指针所指的位置就是要找的倒数第k个位置。

public Node findElem(int k){

              if(k<1||k>this.length())

                       returnnull;

              Nodep1=head;

              Nodep2=head;

              for(int i=0;i

                       p1=p1.next;

              }

              while(p1!=null){

                       p1=p1.next;

                       p2=p2.next;

              }

              return p2;

     }

4.       如何实现链表的反转

例如有三个相邻的点1,2,3,假如经过若干步操作,已经把结点1之前的指针调整完毕,这些结点的next指向前面一个结点。现在遍历到结点2,需要调整结点的next指针,让它指向结点1,需要注意的是一旦调整了指针的指向,链表就断开了,因为已经没有指针指向结点3了,链表就断了。所以需要在调整2的next之前将3保存下来。下面给出非递归方式实现链表的反转。

数据结构基础知识(一)——链表_第2张图片

   publicvoid ReverseIteratively(Node head){

                   NodepReversedHead=head;//反转后的头结点

                   NodepNode=head;//用于遍历的指针

                   NodepPrev=null;//用于保存结点的后继结点

                   while(pNode!=null){

                            NodepNext=pNode.next;

                            if(pNext==null)

                                     pReversedHead=pNode;//如果链表为空,则反转后的链表即为头结点pNode

                       pNode.next=pPrev;//第一次循环时当前结点next指向空,后面指向的自然就是前驱结点了

                       pPrev=pNode;//保存当前结点

                       pNode=pNext;//后移一个结点

                   }

                   this.head=pReversedHead;//遍历完毕head指向PNode(遍历的最后一个结点)

         }

  

你可能感兴趣的:(经验与总结,java基础,算法学习,数据结构)