对链表的基本实现和各种操作

为什么使用链表
好处是插入和删除节点更加高效。
缺点是:查找访问不如数组的读取
需构造一个自己需要的节点类,可设计为嵌套类。

对链表的各种操作进行了复习和总结:

最好先自己按着列表进行尝试实现,更容易发现问题
主要操作:
1. 头插法
2. 尾插法
3. 任意节点插入
4. 删除头节点
5. 删除指定位置节点
6. 删除指定数据节点
7. 删除node节点(不知道头节点)
8. 链表反转
9. 根据位置查找信息
10. 根据数据查找信息
11. 查找中间节点
12. 查找倒数第K个节点
13. 对链表进行排序
14. 删除重复的节点(两种算法)
15. 将链表按指定值分为两部分
16. 判断是否有环
17. 找出环的入口
18. 判断是否是回文链表
19. 两个链表的加法(正序和逆序)

import java.util.Hashtable;//可换为ConcurrentHashMap
import java.util.Stack;

/**
 * 链表的各种操作
 *
 * @author fx50jk
 */
class myNode<T> {

    myNode next;
    T data;

    public myNode(T data) {
        this.data = data;
    }

    public myNode() {
    }

    public void display() {
        System.out.println(this.data);
    }

//
//    @Override
//    public int compare(Object data, Object test) {
//          int c;
//        c = data.compareTo(test);
//        if (c == 0) {
//            return 0;
//        } else if (c > 0) {
//            return 1;
//        } else {
//            return -1;
//        }
//    }
}

class ListNode<T> {

    myNode head;
//    int pos=0;
    int count = 0;

    public ListNode() {
        this.head = null;
    }

    //头插法、相当于栈、插入一个节点先进后出
    public void addTofirst(T data) {
        myNode node = new myNode(data);
        node.next = head;
        head = node;
    }

    //尾插法、相当于队列、先进先出
    public void addTotail(T data) {
        myNode node = new myNode(data);
        myNode temp = head;
        if (temp == null) {
            node.next = head;
            head = node;
        } else {
            while (temp.next != null) {
                temp = temp.next;
            }
            temp.next = node;
        }
    }

    // 在任意位置插入节点 在index的后面插入  
    public void addToIndex(int index, int data) {
        myNode node = new myNode(data);
        myNode current = head;
        myNode previous = head;
        int pos = 0;
        while (pos != index) {
            previous = current;
            current = current.next;
            pos++;
        }
        node.next = current;
        previous.next = node;

    }

    //显示所有节点
    public void display() {
        myNode current = head;
        while (current != null) {
            System.out.println(current.data + "\t");
            current = current.next;
        }
    }

    //长度
    public int length() {
        int length = 0;
        myNode temp = head;
        while (temp != null) {
            length++;
            temp = temp.next;
        }
        return length;
    }

    // 删除一个头结点,并返回头结点  
    public myNode deleteFirstNode() {
        myNode tempNode = head;
        head = tempNode.next;
        return tempNode;
    }

    //删除index节点(知道头节点)
    public boolean deleteNodeByPos(int index) {
        if (index < 1 || index > length()) {
            return false;
        }
        if (index == 1) {
            head = head.next;
            return true;
        }
        int i = 1;
        myNode preNode = head;
        myNode curNode = head;
        while (curNode != null) {
            if (i == index) {
                preNode.next = curNode.next;
                return true;
            }
            preNode = curNode;
            curNode = curNode.next;
            i++;
        }
        return false;
//        myNode current = head;
//        myNode previous = head;
//        int pos=0;
//        while (pos != index) {
//            pos++;
//            previous = current;
//            current = current.next;
//        }
//        if (current == head) {
//            head = head.next;
//        } else {
//            pos = 0;
//            previous.next = current.next;
//        }
//        return current;

    }

    // 根据节点的data删除节点(仅仅删除第一个)  
    public myNode deleteNodeByData(Object data) {
        myNode current = head;
        myNode previous = head; //记住上一个节点  
        while (current.data != data) {
            if (current.next == null) {
                return null;
            }
            previous = current;
            current = current.next;
        }
        if (current == head) {
            head = head.next;
        } else {
            previous.next = current.next;
        }
        return current;
    }

    //删除node节点(不知道头节点),只能访问该节点
    public static boolean deleteNodeByNode(myNode node) {
        if (node == null || node.next == null) {
            return false;
        }
//        Object temp = node.data;
//        node.data = node.next.data;
//        node.next.data = temp;
//        node.next = node.next.next;
//        return true;

        myNode temp = node.next;
        node.data = temp.data;
        node.next = temp.next;
        return true;
    }

    //链表的反转
    public myNode ReverseNode() {
        myNode ReversHead = head;
        myNode rNode = head;
        myNode prev = null;
        while (rNode != null) {
            myNode nextNode = rNode.next;
            if (nextNode == null) {
                ReversHead = rNode;
            }
            rNode.next = prev;
            prev = rNode;
            rNode = nextNode;
        }
        this.head = ReversHead;
        return this.head;
    }

    // 根据位置查找节点信息  
    public myNode findByPos(int index) {
        myNode current = head;
        int pos = 0;
        if (pos != index) {
            current = current.next;
            pos++;
        }

        return current;
    }

    // 根据数据查找节点信息  
    public myNode findByData(Object data) {
        myNode current = head;
        while (current.data != data) {
            if (current.next == null) {
                return null;
            }
            current = current.next;
        }
        return current;
    }

//查找链表的中间节点
 /*快慢指针的方式查找单链表的中间节点,快指针一次走两步,慢指针一次走一步,
     当快指针走完时,慢指针刚好到达中间节点。*/
    public myNode SearchMid() {
        myNode fast = head;
        myNode slow = head;
        while (fast != null && fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    //查找倒数第K个元素
/*采用两个指针P1,P2,P1先前移K步,然后P1、P2同时移动,
     当p1移动到尾部时,P2所指位置的元素即倒数第k个元素 。*/
    public myNode TailK(int k) {
        if (k < 1 || k > length()) {
            return null;
        }
        myNode first = head;
        myNode second = head;

        for (int i = 0; i < k; i++) {
            first = first.next;
        }
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        System.out.println("TailK:" + second.data);
        return second;
    }

    //对链表进行排序
    public void sort() {
        myNode nextNode = null;
        myNode curNode = head;
        Object temp = 0;
        while (curNode.next != null) {
            nextNode = curNode.next;
            while (nextNode != null) {
                if ((int) curNode.data > (int) nextNode.data) {
                    temp = curNode.data;
                    curNode.data = nextNode.data;
                    nextNode.data = temp;
                }
            }
        }
    }

    //删除重复的节点  时间复杂度O(n^2)
    public void deleteDuplecate() {
        myNode current = head;
        while (current != null) {
            myNode temp = current;
            while (temp != null) {
                if (current.data == temp.next.data) {
                    temp.next = temp.next.next;
                } else {
                    temp = temp.next;
                }
            }
            current = current.next;
        }
    }

    //删除重复的元素,时间复杂度大O(n)
    public void deleteDups() {
        Hashtable hashtable = new Hashtable();
        myNode current = head;
        myNode temp = null;
        while (current != null) {
            if (hashtable.containsKey(current.data)) {
                temp.next = current.next;
            } else {
                hashtable.put(current.data, true);
                temp = current;
            }
            current = current.next;
        }
    }

    //以给定值X为基准将链表分割成两部分小于X排在大于等于X之前
    public myNode partitton(Object x) {
        myNode beforeStart = null;
        myNode aferStart = null;
        myNode tempHead = head;
        while (tempHead != null) {
            myNode nextNode = tempHead.next;//记得下一次迭代用的后继节点
            if ((int) tempHead.data < (int) x) {
                //将节点插入到before链表的前端
                tempHead.next = beforeStart;
                beforeStart = tempHead;
            } else {
                tempHead.next = aferStart;
                aferStart = tempHead;
            }
            tempHead = nextNode;
        }
        if (beforeStart == null) {
            return aferStart;
        }
        //定位至before链表的末尾,合并两个链表
        head = beforeStart;
        while (beforeStart.next != null) {
            beforeStart = beforeStart.next;
        }
        beforeStart.next = aferStart;
        return head;

    }

    public myNode partitton1(Object x) {
        myNode beforeStart = null;
        myNode beforeEnd = null;
        myNode aferStart = null;
        myNode afterEnd = null;

        myNode tempHead = head;
        while (tempHead != null) {
            myNode nextNode = tempHead.next;
            tempHead.next = null;
            if ((int) tempHead.data < (int) x) {
                if (beforeStart == null) {
                    beforeStart = tempHead;
                    beforeEnd = beforeStart;
                } else {
                    beforeEnd.next = tempHead;
                    beforeEnd = tempHead;
                }
            } else {
                if (aferStart == null) {
                    aferStart = tempHead;

                    afterEnd = aferStart;
                } else {
                    afterEnd.next = tempHead;
                    afterEnd = tempHead;
                }
            }
            tempHead = nextNode;
        }
        if (beforeStart == null) {
            return aferStart;
        } else {
            beforeEnd.next = aferStart;
            return beforeStart;
        }

    }

    //判断是否有环
    public boolean isLoop() {
        myNode fast = head;
        myNode slow = head;
        if (fast == null) {
            return false;
        }
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                System.out.println("有环");
                return true;
            }
        }
        return !(fast == null || fast.next != null);
    }

    //找到环的入口
    public myNode FindLoopPort() {
        myNode fast = head;
        myNode slow = head;
        //找到碰撞的位置
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                break;
            }
        }

        //错误检查,没有碰撞也没有环路
        if (fast == null || fast.next == null) {
            return null;
        }
        //将slow指向首部,fast指向碰撞处,俩个这距离环路的起始位置K步,
        //若俩个这以相同的速度移动,必定会在环路的起始位置碰撞
        slow = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

    //检查是否是回文链表
    /*1、反转后与原始链表进行比较
     2、迭代法(快慢数组,把满数组里的放入栈中)
     */
    public boolean isPalindrome() {
        myNode fast = head;
        myNode slow = head;
        Stack<T> stack = new Stack<>();
        /*将链表的前半部分元素入栈,当fast到达链表尾部的时候,slow正好到达链表的中间位置*/
        while (fast != null && fast.next != null) {
            stack.push((T) slow.data);
            slow = slow.next;
            fast = fast.next.next;
        }
        //当链表有奇数个元素时,跳过中间元素
        if (fast != null) {
            slow = slow.next;
        }
        //从中间到后面依次和栈里面的元素进行比较
        while (slow != null) {
            T top = stack.pop();
            //判断是否相同
            if (top != slow.data) {
                return false;
            }
            slow = slow.next;
        }
        return true;

    }

    class Result<T> {

        myNode<T> node;
        boolean result;

        public Result(myNode<T> node, boolean result) {
            this.node = node;
            this.result = result;
        }

    }

    private Result isPalindromeRecurse(myNode head, int length) {
        if (head == null || length == 0) {
            return new Result(null, true);
        } else if (length == 1) {
            return new Result(head.next, true);
        } else if (length == 2) {
            return new Result(head.next.next, (int) head.data == (int) head.next.data);
        }
        Result res = isPalindromeRecurse(head.next, length - 2);
        if (!res.result || res.node == null) {
            return res;
        } else {
            res.result = ((int) head.data == (int) res.node.data);
            res.node = res.node.next;
            return res;
        }
    }

    public boolean isPalindrome1() {
        Result temp = isPalindromeRecurse(head, length());
        return temp.result;
    }

    //两个链表的加法(个位在链表的首部)
    public myNode addLists(myNode node1, myNode node2, int carry) {
        //如果两个链表全部为空
        if (node1 == null && node2 == null && carry == 0) {
            return null;
        }
        myNode result = new myNode();
        //将data想加以及进位carry相加
        int value = carry;
        if (node1 != null) {
            value += (int) node1.data;
        }
        if (node2 != null) {
            value += (int) node2.data;
        }
        result.data = value % 10;
        //递归
        myNode more = addLists(node1 == null ? null : node1.next, node2 == null ? null : node2.next, value >= 10 ? 1 : 0);
        result.next = more;
        return result;
    }
    //正向存放的,个位在链表尾部
    //1、如果两个链表不一样长,要进行对位,对短的链表进行补0
    //2、递归时会传入进位,最后还要返回结果需要一个包裹类
//    private class PartialSum{
//        public ListNode sum=null;
//        public int carry=0;
//    }
//    
//    ListNode addLists1(ListNode node1,ListNode node2){
//        int len1=node1.length();
//        int len2=node2.length();
//        //用零填充短链表
//        if (len1<len2) {
//            node1=padList(node1,len2-len1);
//        }
//    }
//    //用零填充
//    ListNode padList(ListNode temp,int padding){
//        ListNode head=temp;
//        for (int i = 0; i < padding; i++) {
//            ListNode n=new ListNode();
//            head.prev=n
//        }
//    }

}

public class charpter2_1 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        ListNode listNode = new ListNode();
        listNode.addTotail(1);
        listNode.addTotail(2);
        listNode.addTotail(3);
        listNode.addTotail(2);

        ListNode.deleteNodeByNode(new myNode(1));
        listNode.display();

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值