基础数据结构(二) 链表


基础数据结构(一):链表

面试经典

约瑟夫问题:丢手绢

丢手绢。所有的人围起来一圈,开始点数,点到几谁就退出。链表的经典算法。

解题思路

数组 和 链表

数组:遍历数组,将每回合出局的至为1 即可

链表:构建一个循环链表 出局删除即可

什么是链表

  1. 链表的定义

    链表通过指针将一组零散的内存块串联在一起。其中,我们把内存块称为链表的“结点”。为了将所有的结点串

    起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址。

  2. 特点

    • ? 不需要连续的内存空间。

    • ? 有指针引用

    • ? 三种最常见的链表结构:【单链表】【双向链表】【循环链表】

单链表

在单链表中,有两个节点是比较特殊的,分别是第一个和最后一个节点,我们称作 【头节点】 和 【尾结点】

【头节点】用来记录链表的基地址。有了它,我们就可以遍历得到整条链表

【尾结点】特殊在指针不是指向下一个,而是指向NULL,表示这是链表的最后一个节点

循环链表

循环链表是一种特殊的单链表。实际上,循环链表也很简单。它跟单链表唯一的区别就在尾结点。我们知道,单链

表的尾结点指针指向空地址,表示这就是最后的结点了。而循环链表的尾结点指针是指向链表的头结点。

它像一个环一样首尾相连,所以叫作“循环”链表。

单向链表

数组与链表区别

重要区别:
1.数组简单易用,在实现上使用的是连续的内存空间,可以借助CPU的缓存机制,预读数组中的数据,所以访问效率更高。

2.链表在内存中并不是连续存储,所以对CPU缓存不友好,没办法有效预读。

3.数组的缺点是大小固定,一经声明就要占用整块连续内存空间。如果声明的数组过大,系统可能没有足够的连续内存空间分配给它,
导致“内存不足(out ofmemory)”。如果声明的数组过小,则可能出现不够用的情况。

4.动态扩容:数组需再申请一个更大的内存空间,把原数组拷贝进去,非常费时。链表本身没有大小的限制,天然地支持动态扩容。

总结

代码太长就不贴出来了(光有思路 直接写 会卡壳)??????

一个算法经典 上面哪个属于使用数据结构解决哦

反转链表

给你单链表的【5->4->3->2->1->null】输出【1->2->3->4->5->null】

两种解决方案

迭代

遍历

定义三个 变量 一个pre 最终的 一个 cur 当前的 一个临时的 可以认为这是三种状态

    ListNode pre = null;
    ListNode cur = head;
    while(cur != null){
        ListNode next = cur.next; // 使用临时对象保存指针 避免丢失
        cur.next = pre; // 将当前指向的指向最终的 比如 1->null 2->1->null 3->2->1->null
  	pre = cur;   // 保存反转成功的
  	cur = next;  // 迭代 
	}
	return pre;

递归

将大问题分解成小问题

public static ListNode reverseList(ListNode head) {
		if (head == null || head.next == null) { // 递归结束条件
			return head; 
		}
		ListNode res = reverseList(head.next); // 从尾结点调用
		head.next.next = head; // 关键代码就这一句
		head.next = null;
		return res;
}