笔记:链表算法之反转链表

链表算法一:反转链表

题目:给定一个带头结点的单链表,按照其逆序输出。

输入:head->1->2->3->4->5->6->7
输出:head->7->6->5->4->3->2->1

注意:由于链表和数组结构不同,单链表中每个结点的地址都储存在其前结点的指针域中,因此,访问任何一个结点只能从链表的头指针开始进行遍历。

方法一:迭代

在遍历列表时,将当前节点的 next 指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针来存储下一个节点。最后返回新的头引用!

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null) return null;
        ListNode pre = null, next = null;
        while(head.next != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        head.next = pre;
        return head;
    }
}

性能分析:这种方法智需要对链表进行一次遍历,所以时间复杂度为O(n)。但是需要额外的变量来保存当前结点的前驱结点和后继结点,所以空间复杂度为O(1)。

方法二:递归

递归法的主要思路是,先逆序除了第一个结点外的子链表(将1-2-3-4-5-6-7变为1-7-6-5-4-3-2),接着把结点1添加到逆序的子列表后面。同理逆序第二个元素依次类推。

class Solution {
    public ListNode reverseList(ListNode head) {
        if (head ==null || head.next == null) {
			return head;
		}
		ListNode pre = reverseList(head.next);
		head.next.next = head;
		head.next = null;
		return pre;
    }
}

性能分析:该算法的也只需遍历链表一次,因此算法的时间复杂度也是O(n),他的优点是思路比较直观。但是由于递归法要不断调用自己,因此会导致性能有所下降。

方法三:利用栈

我们可以利用栈的先入后出性质,可以对链表进行反转

class Solution {
    public ListNode reverseList(ListNode head) {
         if (head ==null||head.next == null) {
			return head;
		}
        Stack <ListNode> stack = new Stack<ListNode>();
        ListNode cur = head;
        while(cur!=null){
            stack.push(new ListNode(cur.val));
            cur  = cur.next;
        }
        cur = stack.pop();
        ListNode newHead = cur;
        while ( !stack.isEmpty() ) {
            cur.next = stack.pop();
            cur = cur.next;
        }
        return newHead;
    }
 }

性能分析:该算法的也需额外的控件,整个过程需要遍历2次链表,即造成了时间的浪费,也造成了空间的浪费。优点:好理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值