当前位置: 首页 > news >正文

数据结构面试知识点总结3

#来自ウルトラマンティガ(迪迦)

1 线性表

最基本、最简单、最常用的一种数据结构。一个线性表是 n 个具有相同特性的数据元素的有限序列。

特征:数据元素之间是一对一的逻辑关系。

  • 第一个数据元素没有前驱,称为头结点;
  • 最后一个数据元素没有后继,称为尾结点;
  • 除了头结点和尾结点,其他数据元素有且仅有一个前驱和一个后继。

分类:

  • 顺序存储
  • 链式存储

2 顺序表

顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元,依次存储线性表中的各个元素。

public class SequenceList<T> implements Iterable<T> {//存储元素的数组private T[] eles;//记录当前顺序表中的元素个数private int N;//构造方法public SequenceList(int capacity) {//初始化数组this.eles = (T[]) new Object[capacity];//初始化长度this.N = 0;}//将一个线性表置为空表public void clear() {this.N = 0;}//判断当前线性表是否为空表public boolean isEmpty() {return N == 0;}//获取线性表的长度public int length() {return N;}//获取指定位置的元素public T get(int i) {return eles[i];}//向线型表中添加元素 tpublic void insert(T t) {if (N == eles.length) {resize(2 * eles.length);}eles[N++] = t;}//在 i 元素处插入元素 tpublic void insert(int i, T t) {if (N == eles.length) {resize(2 * eles.length);}//先把i索引处的元素及其后面的元素依次向后移动一位for (int index = N; index > i; index--) {eles[index] = eles[index - 1];}//再把t元素放到i索引处即可eles[i] = t;//元素个数+1N++;}//删除指定位置i处的元素,并返回该元素public T remove(int i) {//记录索引i处的值T current = eles[i];//索引i后面元素依次向前移动一位即可for (int index = i; index < N - 1; index++) {eles[index] = eles[index + 1];}//元素个数-1N--;if (N < eles.length / 4) {resize(eles.length / 2);}return current;}//查找t元素第一次出现的位置public int indexOf(T t) {for (int i = 0; i < N; i++) {if (eles[i].equals(t)) {return i;}}return -1;}//根据参数newSize,重置eles的大小public void resize(int newSize) {//定义一个临时数组,指向原数组T[] temp = eles;//创建新数组eles = (T[]) new Object[newSize];//把原数组的数据拷贝到新数组即可for (int i = 0; i < N; i++) {eles[i] = temp[i];}}@Overridepublic Iterator<T> iterator() {return new SIterator();}private class SIterator implements Iterator {private int cursor;public SIterator() {this.cursor = 0;}@Overridepublic boolean hasNext() {return cursor < N;}@Overridepublic T next() {return eles[cursor++];}}
}

复杂度:

get(i):时间复杂度 O(1)

insert(int i, T t):时间复杂度 O(n)

remove(int i):时间复杂度 O(n)

3 链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列的结点(链表中的每一个元素称为结点)组成,结点可以在运行时动态生成。

//链表结点
public class Node<T> { //存储元素 public T item; //指向下一个结点 public Node next; public Node(T item, Node next) { this.item = item;this.next = next; } 
}

复杂度:

get(i):时间复杂度 O(n)

insert(int i, T t):时间复杂度 O(1)

remove(int i):时间复杂度 O(1)

3.1 单向链表

单向链表是链表的一种,它由多个结点组成,每个结点都由一个数据域和一个指针域组成,数据域用来存储数据,指针域用来指向其后继结点。链表的头结点的数据域不存储数据,指针域指向第一个真正存储数据的结点。

public class LinkList<T> implements Iterable<T> {//头结点private Node head;//链表的长度private int N;//结点类private class Node {//存储数据T item;//下一个结点Node next;public Node(T item, Node next) {this.item = item;this.next = next;}}public LinkList() {//初始化头结点、this.head = new Node(null, null);//初始化元素个数this.N = 0;}//清空链表public void clear() {head.next = null;this.N = 0;}//获取链表的长度public int length() {return N;}//判断链表是否为空public boolean isEmpty() {return N == 0;}//获取指定位置i出的元素public T get(int i) {//通过循环,从头结点开始往后找,依次找i次,就可以找到对应的元素Node n = head.next;for (int index = 0; index < i; index++) {n = n.next;}return n.item;}//向链表中添加元素tpublic void insert(T t) {//找到当前最后一个结点Node n = head;while (n.next != null) {n = n.next;}//创建新结点,保存元素tNode newNode = new Node(t, null);//让当前最后一个结点指向新结点n.next = newNode;//元素的个数+1N++;}//向指定位置i出,添加元素tpublic void insert(int i, T t) {//找到i位置前一个结点Node pre = head;for (int index = 0; index <= i - 1; index++) {pre = pre.next;}//找到i位置的结点Node curr = pre.next;//创建新结点,并且新结点需要指向原来i位置的结点Node newNode = new Node(t, curr);//原来i位置的前一个节点指向新结点即可pre.next = newNode;//元素的个数+1N++;}//删除指定位置i处的元素,并返回被删除的元素public T remove(int i) {//找到i位置的前一个节点Node pre = head;for (int index = 0; index <= i - 1; i++) {pre = pre.next;}//要找到i位置的结点Node curr = pre.next;//找到i位置的下一个结点Node nextNode = curr.next;//前一个结点指向下一个结点pre.next = nextNode;//元素个数-1N--;return curr.item;}//查找元素t在链表中第一次出现的位置public int indexOf(T t) {//从头结点开始,依次找到每一个结点,取出item,和t比较,如果相同,就找到了Node n = head;for (int i = 0; n.next != null; i++) {n = n.next;if (n.item.equals(t)) {return i;}}return -1;}@Overridepublic Iterator<T> iterator() {return new LIterator();}private class LIterator implements Iterator {private Node n;public LIterator() {this.n = head;}@Overridepublic boolean hasNext() {return n.next != null;}@Overridepublic Object next() {n = n.next;return n.item;}}//用来反转整个链表public void reverse() {//判断当前链表是否为空链表,如果是空链表,则结束运行,如果不是,则调用重载的reverse方法完成反转if (isEmpty()) {return;}reverse(head.next);}//反转指定的结点curr,并把反转后的结点返回public Node reverse(Node curr) {if (curr.next == null) {head.next = curr;return curr;}//递归的反转当前结点curr的下一个结点;返回值就是链表反转后,当前结点的上一个结点Node pre = reverse(curr.next);//让返回的结点的下一个结点变为当前结点curr;pre.next = curr;//把当前结点的下一个结点变为nullcurr.next = null;return curr;}
}

3.2 双向链表

双向链表也叫双向表,是链表的一种,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点。

public class TowWayLinkList<T> implements Iterable<T> {//首结点private Node head;//最后一个结点private Node last;//链表的长度private int N;//结点类private class Node {//存储数据T item;//指向上一个结点Node pre;//指向下一个结点Node next;public Node(T item, Node pre, Node next) {this.item = item;this.pre = pre;this.next = next;}}public TowWayLinkList() {//初始化头结点和尾结点this.head = new Node(null, null, null);this.last = null;//初始化元素个数this.N = 0;}//清空链表public void clear() {this.head.next = null;this.head.pre = null;this.head.item = null;this.last = null;this.N = 0;}//获取链表长度public int length() {return N;}//判断链表是否为空public boolean isEmpty() {return N == 0;}//获取第一个元素public T getFirst() {if (isEmpty()) {return null;}return head.next.item;}//获取最后一个元素public T getLast() {if (isEmpty()) {return null;}return last.item;}//插入元素tpublic void insert(T t) {if (isEmpty()) {//如果链表为空://创建新的结点Node newNode = new Node(t, head, null);//让新结点称为尾结点last = newNode;//让头结点指向尾结点head.next = last;} else {//如果链表不为空Node oldLast = last;//创建新的结点Node newNode = new Node(t, oldLast, null);//让当前的尾结点指向新结点oldLast.next = newNode;//让新结点称为尾结点last = newNode;}//元素个数+1N++;}//向指定位置i处插入元素tpublic void insert(int i, T t) {//找到i位置的前一个结点Node pre = head;for (int index = 0; index < i; index++) {pre = pre.next;}//找到i位置的结点Node curr = pre.next;//创建新结点Node newNode = new Node(t, pre, curr);//让i位置的前一个结点的下一个结点变为新结点pre.next = newNode;//让i位置的前一个结点变为新结点curr.pre = newNode;//元素个数+1N++;}//获取指定位置i处的元素public T get(int i) {Node n = head.next;for (int index = 0; index < i; index++) {n = n.next;}return n.item;}//找到元素t在链表中第一次出现的位置public int indexOf(T t) {Node n = head;for (int i = 0; n.next != null; i++) {n = n.next;if (n.next.equals(t)) {return i;}}return -1;}//删除位置i处的元素,并返回该元素public T remove(int i) {//找到i位置的前一个结点Node pre = head;for (int index = 0; index < i; index++) {pre = pre.next;}//找到i位置的结点Node curr = pre.next;//找到i位置的下一个结点Node nextNode = curr.next;//让i位置的前一个结点的下一个结点变为i位置的下一个结点pre.next = nextNode;//让i位置的下一个结点的上一个结点变为i位置的前一个结点nextNode.pre = pre;//元素的个数-1N--;return curr.item;}@Overridepublic Iterator<T> iterator() {return new TIterator();}private class TIterator implements Iterator {private Node n;public TIterator() {this.n = head;}@Overridepublic boolean hasNext() {return n.next != null;}@Overridepublic Object next() {n = n.next;return n.item;}}
}

3.3 循环链表

链表整体要形成一个圆环状。让单向链表的最后一个节点的指针指向头结点。

4 题目

4.1 反转链表

LeetCode:24 题

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
class Solution {public ListNode reverseList(ListNode head) {ListNode pre = null;ListNode cur = head;while(cur != null) {ListNode tmp =  cur.next;cur.next = pre;pre = cur;cur = tmp;}return pre;}
}

4.2 快慢指针

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

示例:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
public class Solution {public boolean hasCycle(ListNode head) {//快慢指针if(head == null || head.next == null) return false;ListNode slow = head;ListNode fast = head.next;while(slow != fast){if(fast == null || fast.next == null) return false;slow = slow.next;fast = fast.next.next;}return true;}
}
http://www.lryc.cn/news/405316.html

相关文章:

  • python-爬虫实例(5):将进酒,杯莫停!
  • AGI 之 【Hugging Face】 的【从零训练Transformer模型】之二 [ 从零训练一个模型 ] 的简单整理
  • 十大排序的稳定性和时间复杂度
  • 【系列教程之】1、点亮一个LED灯
  • 搜维尔科技:Manus Metagloves使用精确的量子跟踪技术捕捉手部每一个细节动作
  • 机器学习 | 阿里云安全恶意程序检测
  • python打包exe文件-实现记录
  • 基本的DQL语句-单表查询
  • Vue3 对比 Vue2
  • 2024中国大学生算法设计超级联赛(1)
  • offer题目51:数组中的逆序对
  • 45、PHP 实现滑动窗口的最大值
  • 【计算机视觉】siamfc论文复现实现目标追踪
  • 数学建模学习(111):改进遗传算法(引入模拟退火、轮盘赌和网格搜索)求解JSP问题
  • Golang | Leetcode Golang题解之第241题为运算表达式设计优先级
  • Unity客户端接入原生Google支付
  • Spring Cloud之五大组件
  • 在 CentOS 7 上安装 Docker 并安装和部署 .NET Core 3.1
  • redis的学习(一):下载安装启动连接
  • 前端设计模式面试题汇总
  • linux(CentOS、Ubuntu)安装python3.12.2环境
  • CSS 中border-radius 属性
  • 【大数据专题】数据仓库
  • go关于string与[]byte再学深一点
  • Qt 实战(7)元对象系统 | 7.4、属性系统:深度解析与应用
  • Docker核心技术:容器技术要解决哪些问题
  • sklearn中的增量学习:特征提取的艺术
  • PostgreSQL 中如何处理数据的唯一性约束?
  • VAE论文阅读
  • 【数据分享】2013-2022年我国省市县三级的逐月SO2数据(excel\shp格式\免费获取)