赞
踩
目录
链表(Linked List)是一种常见的数据结构,它由节点(Node)组成,每个节点包含两部分:数据域(存储元素值)和指针域(指向下一个节点)。链表使用指针来连接各个节点,形成一个逻辑上的序列。
常见的链表类型有单向链表、双向链表和循环链表。
单向链表(Singly Linked List):每个节点只包含一个指针,指向下一个节点。最后一个节点指向 null,表示链表的结束。
双向链表(Doubly Linked List):每个节点包含两个指针,分别指向前一个节点和后一个节点。首节点的前置指针和尾节点的后置指针都指向 null。
循环链表(Circular Linked List):在单向链表或双向链表的基础上,将尾节点的指针指向首节点(或将首节点的前置指针指向尾节点),形成一个环形结构。
首先我们将所有的方法放在一个接口里。
将链表的常见操作放在接口中,可以方便类的实现对这些操作进行统一的定义和实现。这样做的好处就是可以在不同的类中使用相同的方法名,而无需考虑具体实现细节。接口定义了一组行为规范,同一个接口的多个实现类可以共用该接口提供的方法,从而实现代码的复用和扩展。对于链表这种数据结构,许多常见的操作都是固定的,将其定义在接口中可以让其他类更容易地调用和重用这些方法。此外,将链表的常见操作封装在接口中,可以使代码更加抽象化,并隐藏底层实现细节。这有助于提高代码的可读性、可维护性和可扩展性,同时也可以使代码更加安全,减少出错的可能性。
同时我们创建一个链表。
1.1头插法
void addFirst (int data);
- @Override
- public void addFirst(int data) {
- ListNode node = new ListNode(data);
-
- if(head == null){
- this.head = node;
- }else {
- node.next = head;
- this.head = node;
- }
- }
1.2尾插法
void addLast(int data);
- @Override
- public void addLast(int data) {
- ListNode node = new ListNode(data);
-
- ListNode cur = this.head;
- if (head == null){
- this.head = node;
- }else{
- while (cur.next != null){
- cur = cur.next;
- }
- cur.next = node;
- }
- }
1.3任意位置插入,第一个数据节点为0号下标
void addIndex(int index,int data);
- @Override
- public void addIndex(int index, int data) {
- if (index < 0 || index > size()) {
-
- return;
- }
- if (index == 0) {
- addFirst(data);
- return;
- }
- if (index == size()) {
- addLast(data);
- return;
- }
-
- ListNode cur = searchPrev(index);
- ListNode node = new ListNode(data);
-
- node.next = cur.next;
- cur.next = node;
- }
1.4查找是否包含关键字为key的节点
boolean contains(int key);
- public ListNode FindKthToTail(int k){
- if(k <= 0 || head ==null){
- return null;
- }
- ListNode fast = head;
- ListNode slow = head;
-
- int count = 0;
- while (k-1 !=count) {
- fast = fast.next;
- //处理k太大的问题
- if(fast == null){
- return null;
- }
- count++;
- }
- while (fast.next != null){
- fast = fast.next;
- slow = slow.next;
- }
- return slow;
- }
首先,检查输入的 k 是否小于等于 0 或者链表 head 是否为 null。如果满足其中任一条件,说明无法找到倒数第 k 个节点,返回 null。
初始化两个指针 fast 和 slow,均指向头节点 head。使用一个计数器 count 来记录当前遍历到的节点位置,初始值为 0。
在 while 循环中,当 count 不等于 k-1 时,将 fast 指针向后移动一位,并递增 count 的值。这样做的目的是为了使 fast 指针领先 slow 指针 k-1 个节点。
在移动 fast 指针时,需要处理 k 大于链表长度的情况。即当 fast 指针移动到末尾时(fast == null),说明 k 太大,无法找到倒数第 k 个节点,返回 null。
当 fast 指针移动到末尾时,slow 指针所指的节点即为倒数第 k 个节点。
最后,返回 slow 指针所指的节点作为结果。
1.5删除第一次出现关键字为key的节点
void remove(int key);
- @Override
- public void remove(int key) {
- if(this.head == null){
- return;
- }
- if(this.head.val == key){
- this.head = this.head.next;
- return;
- }
-
- ListNode cur = findPrev(key);
-
- if(cur == null){
- System.out.println("没有你要删除的数字");
- return;
- }
-
- ListNode del = cur.next;
- cur.next = del.next;
- }
-
- private ListNode findPrev(int key){
- ListNode cur = this.head;
- while (cur.next != null){
- if(cur.next.val == key){
- return cur;
- }
- cur = cur.next;
- }
- return null;
- }
首先,检查头节点 head 是否为 null。如果链表为空,则直接返回。
检查头节点的值是否等于要删除的值 key。如果相等,说明要删除的节点就是头节点,将头节点的下一个节点作为新的头节点即可,然后返回。
如果头节点不是要删除的节点,需要找到要删除节点的前一个节点 cur。调用 findPrev 方法来寻找对应值为 key 的节点的前一个节点。
当 cur 为 null 时,说明找不到要删除的值 key,输出提示信息并返回。
如果能找到要删除的节点的前一个节点 cur,将要删除的节点 del 设置为 cur 的下一个节点 cur.next。
将 cur 的 next 指针指向 del 的下一个节点 del.next,从而跳过 del 节点,实现删除操作。
1.6打印
void display();
- @Override
- public void display() {
- ListNode cur = this.head;
- while (cur != null){
- System.out.print(cur.val+" ");
- cur = cur.next;
- }
- }
以上就是今天要讲的内容,有什么不对的地方欢迎大家指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。