数据结构之链表及其栈和队列的实现

链表的基本操作

定义

class Node{
  Item item;//表示任意的数据类型
  Node next;//指向下一个节点的引用
}

从链表头部插入元素

Node oldFirst = first;//oldFirst指向原来的头结点
first = new Node();
first.item = item;
first.next = oldFirst;

从链表头部删除元素

first = first.next; //first指向first.next即可

从链表尾部插入元素

Node oldLast = last;
last = new Node();
last.item = item;
oldLast.next = last;

从中间插入和删除结点

Node first = new Node();
Node third = new Node();
first.next = third;
//在first和second之间插入second
Node second = new Node();
first.next = second;
second.next = third;
//删除second结点(删除结点必须知道前一个结点)
first.next = third;

栈和对列的实现

栈的实现

使用数组实现栈

public class ArrayStack<Item> implements Iterable<Item>{

    //初始化数组的大小
    private Item[] arr = (Item[])new Object[5];
    private int N == 0;
    
    public int size(){
        return N;
    }
    
    public boolean isEmpty(){
        return N == 0 ? true : false; 
    }
    
    public void push(Item item){
        if(N == arr.length){
            resize(2*N);
        }
        arr[N++] = item;
    }
    
    public Item pop(){
        Item item = arr[--N];
        arr[N] = null;
        if(N > 0 && N == arr.length/4){
            resize(2*N);
        }
        return item;
    }
    //动态调整数组大小
    public void resize(int capacity){
        Item[] temp = (Item[])new Object[capacity];
        for(int i = 0; i < N; i++){
           temp[i] = arr[i];
        }
        arr = temp;
    }
    
    //实现迭代器功能,可以使用foreach语句
    public Iterator<Item> iterator(){
        return new ArrayReverseIterator();
    }
    
    private class ArrayReverseIterator implements Iterator<Item>{
        private int index = N;
        public boolean hasNext(){
            return N > 0 ? true : false;
        }
        
        public Item next(){
            return arr[--N];
        }
    }
}

使用链表实现栈

public class NodeStack<Item> implements Iterable<Item> {

    private class Node{
        Item item;
        Node next;
    }

    private Node first;
    private int N = 0;

    public void push(Item item){
        Node oldfirst = first;
        first = new Node();
        first.item = item;
        first.next = oldfirst;
        N++;
    }

    public Item pop(){
        Item item = first.item;
        first = first.next;
        N--;
        return item;
    }

    public boolean isEmpty(){
        return N == 0;
    }

    public int size(){
        return N;
    }

    @Override
    public Iterator<Item> iterator() {
        return new ListIterator();
    }


    private class ListIterator implements Iterator<Item>{

        private Node current = first;

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public Item next() {
            Item item = current.item;
            current = current.next;
            return item;
        }
    }

}

队列的实现

public class Queue<Item> implements Iterable<Item>{
    
    private class Node{
        Item item;
        Node next;
    }
    
    Node first;
    Node last;
    private int N = 0;
    
    public boolean isEmpty(){
        return N == 0;
    }
    
    public int size(){
        return N;
    }
    
    public void enqueue(Item item){
        Node oldLast = last;
        last = new Node();
        last.item = item;
        if(isEmpty()){
            first = last;
        }else{
            oldLast.next = last;
        }
        N++;
    }
    
    public Item dequeue(){
        Item item = first.item;
        first = first.next;
        if(isEmpty()){
            last = null;
        }
        N--;
        return item;
    }
    
    public Iterator<Item> iterator(){
       return new QueueIterator();
    }
    
    private class QueueIterator implements Iterator<Item>{
        
        private Node current = first;
        
        public boolean hasNext(){
            return current != null;
        }
        
        public Item next(){
            Item item = current.item;
            current = current.next;
            return item;
        }
        
    }
    
}

链表练习题目

1.有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序.给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。

class ListNode{
    int val;
    ListNode next;
    public ListNode(int val){
      this.val = val;
    }
}
public ListNode insert(int[] A, int[] next, int val){
    
    if(A == null || A.length == 0){
        ListNode node = new ListNode(val);
        return node;
    }
    ListNode head = new ListNode(A[0]);
    ListNode point = head;
    ListNode current = null;
    //通过数组构造链表
    for(int i = 0; i < next.length - 1; i++){
        current = new ListNode(A[next[i]]);
        ponit.next = current;
        point = current;
    }
    
    
    if(val < head.val){
        ListNode node = new ListNode(val);
        node.next = head;
        head = node;
        return head;
    }
    
    if(val > current.val){
       ListNode node = new ListNode(val);
       current.next = node;
       return head;
    }
    
    ListNode p1 = head;
    ListNode p2 = head.next;
    while(p1 != null && p2 != null){
        if(p1.val <= val && val <= p2.val){
            ListNode node = new ListNode(val);
            p1.next = node;
            node.next = p2;
            return head;
        }else{
            p1 = p1.next;
            p2 = p2.next;
        }
    }
    
    return head;
    
    
}

2.实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true.

public boolean remove(ListNode pNode){
        if(pNode.next == null){
            return false;
        }
        pNode.val = pNode.next.val;
        pNode.next = pNode.next.next;
        return true;
}

3.对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。

public ListNode listDivide(ListNode head,int val){

    public ListNode head_1 = null;
    public ListNode tail_1 = null;
    public ListNode head_2 = null;
    public ListNode tail_2 = null;
    public ListNode next = null;
    
    while(head != null){
       next = head.next;
       head.next = null;
       if(head.val <= val){
          ListNode oldTail_1 = tail_1;
          tail_1 = head;
          if(head_1 == null){
            head_1 = tail_1;
          }else{
            oldtail_1.next = tail_1;
          }
       }else if(head.val > val){
          ListNode oldTail_2 = tail_2;
          tail_2 = head;
          if(head_2 == null){
             head_2 = tail_2;
          }else{
             oldTail_2.next = tail_2;
          }
       }
       head = next;
    }
    
    if(tail_1 != null){
      tail_1.next = head_2;
    }
    
    return head_1 != null ? head_1 : head_2; 
    
}

4.有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。

public ListNode inverse(ListNode head,int k){
    if(head == null || head.next == null || k < 2){
        return head;
    }
    ListNode pre = null;
    ListNode current = head;
    ListNode start = null;
    ListNode next = null;
    int count = 1;
    while(current != null){
        next = current.next;
        if(count == 3){
            start = pre == null ? head : pre.next;
            head = pre == null ? current : head;
            reverse(pre,start,current,next);
            pre = start;
            count = 0;
        }
        count++;
        current = next;
    }
    return head;
    
}

//先逆序k个节点
public void reverse(ListNode left,ListNode start,ListNode end,ListNode right){
    ListNode current = start.next;
    ListNode point = start;
    ListNode next = null;
    while(current != right){
        next = current.next;
        current.next = point;
        point = current;
        current = next;
    }
    if(left != null){
        left.next = end;
    }
    start.next = right;
}



5.如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。

 public int chkLoop(ListNode head, int adjust) {
        if(head == null){
            return -1;
        }
        boolean isCircle = false;
        ListNode fast = head;
        ListNode slow = head;
        while(slow != null && fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                isCircle = true;
                break;
            }
        }
        if(!isCircle){
            return -1;
        }
        fast = head;
        while(slow != fast){
            slow = slow.next;
            fast = fast.next;
        }
        return slow.val;

    }

6.现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m), 额外空间复杂度为O(1)的算法,判断这两个链表是否相交。

public boolean chkIntersect(ListNode headA, ListNode headB) {

        if(headA == null || headB == null){
            return false;
        }
        boolean isIntersect = false;
        int lenA = 0;
        ListNode p1 = headA;
        while(p1 != null){
            p1 = p1.next;
            lenA++;
        }
        int lenB = 0;
        ListNode p2 = headB;
        while(p2 != null){
            p2 = p2.next;
            lenB++;
        }
        if(lenA >= lenB){
            isIntersect = isCrossing(headA,headB,lenA - lenB);
        }else{
            isIntersect = isCrossing(headB,headA,lenB - lenA);
        }
        return isIntersect;
    }

public boolean isCrossing(ListNode headA, ListNode headB, int num){
        ListNode curA = headA;
        boolean isCross = false;
        while(num != 0){
            curA = curA.next;
            num--;
        }
        ListNode curB = headB;
        while(curA != null && curB != null){
            if(curA == curB){
                isCross = true;
                break;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return isCross;
    }

7.如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不想交的话返回空。

public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {

        if(head1 == null || head2 == null){
            return false;
        }

        ListNode p1 = insert(head1);
        ListNode p2 = insert(head2);
        //入环节点相交
        if(p1 == p2){
            return true;
        }
        //环中相交
        ListNode start1 = p1.next;
        while(start1 != p1){
            if(start1 == p2){
                return true;
            }
            start1 = start1.next;
        }
        return false;
    }

    //入环节点
    public ListNode insert(ListNode head){
        ListNode slow = head;
        ListNode fast = head;
        while(slow != null && fast != null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                break;
            }
        }
        fast = head;
        while(slow != fast){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容