目录

  • 线性表
    • 一、顺序表
      • 1、使用顺序表MyArrayList增删查改
        • MyArrayList.java
        • TestDemo.java
    • 二、链表
      • 1、带头 / 不带头 循环 / 非循环
      • 2、创建链表并访问
      • 3、无头单向非循环链表实现增删查改
        • 3.1、头插法
        • 3.2、尾插法
        • 3.3、任意位置插入
        • 3.4、删除第一次出现关键字为key的节点
        • 3.5、删除所有值为key的节点,返回删除后链表的head --> 遍历链表一遍
        • 3.6、清空链表
        • MylinkedList.java
      • 4、力扣OJ
        • 4.1、反转一个单链表
        • 4.2、返回链表的中间结点
        • 4.3、输入一个链表,输出该链表中倒数第k个结点
        • 4.4、合并链表
        • 4.5、以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前
        • 4.6、删除链表重复节点
        • MylinkedList.java
        • TestDemo.java
        • 4.7、链表的回文结构
        • 4.8、输入两个链表,找出它们的第一个公共结点
        • 4.9、给定一个链表,判断链表中,是否有环
        • 4.10、给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
        • 4.11、选择题
      • 5、无头双向链表增删查改
        • MylinkedList.java
        • TestDemo.java
      • 6、实现双向链表(带傀儡节点)
        • MylinkedList.java
    • 三、总结

线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储


一、顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改
为什么不直接用数组:写到类里,以后就可以面向对象

1、使用顺序表MyArrayList增删查改

MyArrayList.java
import java.util.Arrays;public class MyArrayList {public int[] elem;public int usedsize; // 当前有效的数据个数public MyArrayList() {this.elem = new int[10];}// 1、打印顺序表public void display() {for (int i = 0; i < usedsize; i++) {System.out.print(this.elem[i]+" ");}System.out.println();}// 2、获取顺序表的有效长度public int size() {return this.usedsize;}public boolean isFull() {return this.usedsize == this.elem.length;}// 3、在 pos 位置新增元素public void add(int pos, int data) {if(pos < 0 || pos > usedsize) {System.out.println("pos 位置不合法!");return;}if(isFull()) {this.elem = Arrays.copyOf(this.elem, 2*this.elem.length);// 扩容后的数组}for (int i = usedsize-1; i >= pos; i--) {this.elem[i+1] = this.elem[i];}this.elem[pos] = data;this.usedsize++;}// 4、判定是否包含某个元素public boolean contains(int toFind) {for (int i = 0; i < this.usedsize; i++) {if(this.elem[i] == toFind) {return true;}}return false;}// 5、查找某个元素对应的位置public int search(int toFind) {for (int i = 0; i < this.usedsize; i++) {if(this.elem[i] == toFind) {return i;}}return -1;}public boolean isEmpty() {return this.usedsize == 0;}// 6、获取 pos 位置的元素public int getPos(int pos) {if(pos < 0 || pos >= usedsize) {System.out.println("pos 位置不合法!");return -1; // 不考虑业务上的处理-1 后期可以抛异常}if(isEmpty()) {System.out.println("顺序表为空!");return -1;}return this.elem[pos];}// 7、给 pos 位置的元素设为 valuepublic void setPos(int pos, int value) {if(pos < 0 || pos >= usedsize) {System.out.println("pos 位置不合法!");return;}if(isEmpty()) {System.out.println("顺序表为空!");return;}this.elem[pos] = value;}// 8、删除第一次出现的关键字keypublic void remove(int toRemove) {if(isEmpty()) {System.out.println("顺序表为空!");return;}int index = search(toRemove);if(index == -1) {System.out.println("没有你要删除的数!");return;}for (int i = index; i < this.usedsize - 1; i++) {this.elem[i] = this.elem[i+1];}this.usedsize--;// this.elem[usedsize] = null; // 如果数组里是引用数据类型}// 9、清空顺序表public void clear() {this.usedsize = 0;/*引用类型:for (int i = 0; i < usedsize; i++) {this.elem[i] = null;}*/}}
TestDemo.java
public class TestDemo {public static void main(String[] args) {MyArrayList myArrayList = new MyArrayList();myArrayList.add(0, 11);myArrayList.add(1, 22);myArrayList.add(2, 33);myArrayList.display(); // 11 22 33System.out.println(myArrayList.contains(3)); // falseSystem.out.println(myArrayList.getPos(1)); // 22myArrayList.setPos(0, 99);myArrayList.display(); // 99 22 33myArrayList.remove(99);myArrayList.display(); // 22 33System.out.println("==================");myArrayList.clear();myArrayList.display();}
}

二、链表

顺序表的缺陷:
1、插入和删除元素,必须移动元素 O(N)
2、扩容- 2倍,浪费空间

能不能做到放1个,给1个空间,插入和删除不移动元素O(1):
使用链表

为何会有这么多的数据结构:描述和组织数据的方式不一样

链表的结构非常多样,以下情况组合起来就有8种链表结构

     单向、双向带头、不带头循环、非循环单向 带头 循环         双向 带头 循环单向 带头 非循环       双向 带头 非循环单向 不带头 循环       双向 不带头 循环*单向 不带头 非循环     *双向 不带头 非循环


1、带头 / 不带头 循环 / 非循环



2、创建链表并访问

// MylinkedList.java
class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}
}public class MyLinkedList {// 成员变量 属于对象public ListNode head; // 链表的头引用public void creatList() {ListNode listNode1 = new ListNode(12);ListNode listNode2 = new ListNode(23);ListNode listNode3 = new ListNode(34);ListNode listNode4 = new ListNode(45);ListNode listNode5 = new ListNode(56);listNode1.next = listNode2;listNode2.next = listNode3;listNode3.next = listNode4;listNode4.next = listNode5;this.head = listNode1;}public void display() {ListNode cur = this.head;while(cur != null) {System.out.print(cur.val+" ");cur = cur.next;}System.out.println();}// 少打印一个 this.head.next != null/*  while(this.head != null) {System.out.print(this.head.val+" ");this.head = this.head.next;} */
}// TestDemo.java
public class TestDemo {public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.creatList();myLinkedList.display();// 12 23 34 45 56}
}

3、无头单向非循环链表实现增删查改

val:数据域
next:下一个节点的地址

3.1、头插法

public void addFirst(int data) {ListNode node = new ListNode(data);node.next = this.head;this.head = node;// 当链表没有元素时/*if(this.head == null) {this.head = node;} else {node.next = this.head;this.head = node;}*/}//
public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(12);myLinkedList.addFirst(23);myLinkedList.addFirst(34);myLinkedList.addFirst(45);myLinkedList.addFirst(56);myLinkedList.display();// 56 45 34 23 12 头插法 每次放在前面}

3.2、尾插法

public void addLast(int data) {ListNode node = new ListNode(data);if (this.head == null) {this.head = node;} else {ListNode cur = this.head;while (cur.next != null) {cur = cur.next;}cur.next = node;}}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);myLinkedList.display();// 12 23 34 45 56 尾插法 可与头插一起使用}

3.3、任意位置插入

public void addIndex(int index, int data) {if (index < 0 || index > size()) {System.out.println("index 位置不合法!");return;}if (index == 0) {addFirst(data);return;}if (index == size()) {addLast(data);return;}ListNode cur = findIndex(index);ListNode node = new ListNode(data);node.next = cur.next;cur.next = node;}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);myLinkedList.display();// 12 23 34 45 56// 任意插入myLinkedList.addIndex(0, 99);myLinkedList.display(); // 99 12 23 34 45 56myLinkedList.addIndex(6, 99);myLinkedList.display(); // 99 12 23 34 45 56 99myLinkedList.addIndex(3, 99);myLinkedList.display(); // 99 12 23 99 34 45 56 99}

3.4、删除第一次出现关键字为key的节点

/*** 找到要删除的key 的前驱
*/
public ListNode searchPerv(int key) {ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {return cur;}cur = cur.next;}return null;
}public void remove(int key) {if (this.head == null) {System.out.println("单链表为空,无法删除!");return;}if (this.head.val == key) {this.head = this.head.next;return;}ListNode cur = searchPerv(key);if (cur == null) {System.out.println("没有你要删除的节点!");return;}ListNode del = cur.next;cur.next = del.next;}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);myLinkedList.display();myLinkedList.remove(12);myLinkedList.display(); // 删除12 --> 23 34 45 56myLinkedList.remove(56);myLinkedList.display(); // 删除56 --> 23 34 45myLinkedList.remove(34);myLinkedList.display(); // 删除34 --> 23 45}

3.5、删除所有值为key的节点,返回删除后链表的head --> 遍历链表一遍

【O链接】

public ListNode removeAllKey(int key) {if (this.head == null) return null;ListNode prev = this.head;ListNode cur = this.head.next;while (cur != null) {if (cur.val == key) {prev.next = cur.next;cur = cur.next;} else {prev = cur;cur = cur.next;}}// 头节点是key:if (this.head.val == key) {this.head = this.head.next;}return this.head;}

3.6、清空链表
public void clear() {// 粗暴方式// this.head = null;while(this.head != null) {ListNode curNext = head.next;this.head.next = null;this.head = curNext;}}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);myLinkedList.display();myLinkedList.clear();System.out.println("xxxxxxxxx");}


MylinkedList.java
class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}
}public class MyLinkedList {public ListNode head;public void creatList() {ListNode listNode1 = new ListNode(12);ListNode listNode2 = new ListNode(23);ListNode listNode3 = new ListNode(34);ListNode listNode4 = new ListNode(45);ListNode listNode5 = new ListNode(56);listNode1.next = listNode2;listNode2.next = listNode3;listNode3.next = listNode4;listNode4.next = listNode5;this.head = listNode1;}public void display() {ListNode cur = this.head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}// 查找是否包含关键字key是否在单链表当中public boolean contains(int key) {ListNode cur = this.head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}// 得到单链表的长度public int size() {int cnt = 0;ListNode cur = this.head;while (cur != null) {cnt++;cur = cur.next;}return cnt;}// 头插法public void addFirst(int data) {ListNode node = new ListNode(data);node.next = this.head;this.head = node;// 当链表没有元素时/*if(this.head == null) {this.head = node;} else {node.next = this.head;this.head = node;}*/}// 尾插法public void addLast(int data) {ListNode node = new ListNode(data);if (this.head == null) {this.head = node;} else {ListNode cur = this.head;while (cur.next != null) {cur = cur.next;}cur.next = node;}}/*** 找到index-1 的位置的节点的地址** @param index* @return*/public ListNode findIndex(int index) {ListNode cur = this.head;while (index - 1 != 0) {cur = cur.next;index--;}return cur;}// 任意位置插入,第一个数据节点为0号下标public void addIndex(int index, int data) {if (index < 0 || index > size()) {System.out.println("index 位置不合法!");return;}if (index == 0) {addFirst(data);return;}if (index == size()) {addLast(data);return;}ListNode cur = findIndex(index);ListNode node = new ListNode(data);node.next = cur.next;cur.next = node;}/*** 找到要删除的key 的前驱** @param key* @return*/public ListNode searchPerv(int key) {ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {return cur;}cur = cur.next;}return null;}// 删除第一次出现关键字为key的节点public void remove(int key) {if (this.head == null) {System.out.println("单链表为空,无法删除!");return;}if (this.head.val == key) {this.head = this.head.next;return;}ListNode cur = searchPerv(key);if (cur == null) {System.out.println("没有你要删除的节点!");return;}ListNode del = cur.next;cur.next = del.next;}// 删除所有值为key的节点,返回删除后链表的head --> 遍历链表一遍public ListNode removeAllKey(int key) {if (this.head == null) return null;ListNode prev = this.head;ListNode cur = this.head.next;while (cur != null) {if (cur.val == key) {prev.next = cur.next;cur = cur.next;} else {prev = cur;cur = cur.next;}}// 头节点是key:if (this.head.val == key) {this.head = this.head.next;}return this.head;// 删除链表中等于给定值 **val** 的所有节点。// [OJ链接](https://leetcode-cn.com/problems/removelinked-list-elements/description/)}public void clear() {// 粗暴方式// this.head = null;while(this.head != null) {ListNode curNext = head.next;this.head.next = null;this.head = curNext;}}
}// TestDemo.java
public class TestDemo {public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.creatList();myLinkedList.display();// 12 23 34 45 56}
}

4、力扣OJ

4.1、反转一个单链表

【OJ】链接

/**
* 从指定头节点开始打印
* @param newHead
*/
public void display2(ListNode newHead) {ListNode cur = newHead;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();
}public ListNode reverseList() {if(this.head == null)  {return null;}ListNode prev = null;ListNode cur = this.head;while(cur != null) {ListNode curNext = cur.next;cur.next = prev;prev = cur;cur = curNext;}return prev;}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.display();ListNode ret = myLinkedList.reverseList();myLinkedList.display2(ret); // 56 45 34 23 12
}


4.2、返回链表的中间结点

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点
【OJ】链接

 // 偶数第二个public ListNode middleNode() {if(this.head == null) {return null;}ListNode fast = this.head;ListNode slow = this.head;while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}return slow;}// 偶数第一个public ListNode middleNode1() {if(this.head == null) {return null;}ListNode fast = this.head;ListNode slow = this.head;while(fast != null && fast.next != null) {fast = fast.next.next;if(fast == null) {return slow;}slow = slow.next;}return slow;}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.display();ListNode even = myLinkedList.middleNode(); // 偶数第二个System.out.println(even.val); // 34ListNode even2 = myLinkedList.middleNode1(); // 偶数第一个System.out.println(even2.val); // 23myLinkedList.addLast(56);ListNode odd = myLinkedList.middleNode(); // 奇数System.out.println(odd.val); // 34}


4.3、输入一个链表,输出该链表中倒数第k个结点

【OJ链接】

 public ListNode findKthToTail(int k) {if(k < 0 || head == null) {return null;}ListNode fast = this.head;ListNode slow = this.head;while(k-1 != 0) {fast = fast.next;if(fast == null) {return null;}k--;}while(fast.next != null) {fast = fast.next;slow = slow.next;}return slow;}public static void main3(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);myLinkedList.display();ListNode ret = myLinkedList.findKthToTail(3);System.out.println(ret.val); // 34}


4.4、合并链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
【OJ】链接

public ListNode mergeTwoLists(ListNode headA, ListNode headB) {ListNode newHead = new ListNode(-1);ListNode tmp = newHead;while(headA != null && headB != null) {if (headA.val < headB.val) {tmp.next = headA;headA = headA.next;tmp = tmp.next;} else {tmp.next = headB;headB = headB.next;tmp = tmp.next;}}if (headA != null) {tmp.next = headA;}if (headB != null) {tmp.next = headB;}return newHead.next;}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);MyLinkedList myLinkedList2 = new MyLinkedList();myLinkedList2.addLast(13);myLinkedList2.addLast(24);myLinkedList2.addLast(30);ListNode ret = myLinkedList.mergeTwoLists(myLinkedList.head, myLinkedList2.head);myLinkedList.display2(ret); // 12 13 23 24 30 34 45}


4.5、以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

【OJ】链接

public ListNode partition(int x) {ListNode bs = null;ListNode be = null;ListNode as = null;ListNode ae = null;ListNode cur = this.head;while (cur != null) {if(cur.val < x) {// 第一次if(bs == null) {bs = cur;be = cur;}else {// 非首次be.next = cur;be = be.next;}}else {// 第一次if(as == null) {as = cur;ae = cur;}else {// 非首次ae.next = cur;ae = ae.next;}}cur = cur.next;}// 预防第一个段为空if(bs == null) {return as;}// 串be.next = as;// 预防第二个段中的数据 最后一个节点不是空if(as != null) {ae.next = null;}return bs;}


4.6、删除链表重复节点

【OJ】链接

public ListNode deleteDuplication() {ListNode cur = head;ListNode newHead = new ListNode(-1);ListNode tmp = newHead;while(cur != null) {if(cur.next != null && cur.val == cur.next.val) {while(cur.next != null && cur.val == cur.next.val) {cur = cur.next;}cur = cur.next;}else {tmp.next = cur;tmp = tmp.next;cur = cur.next;}}// 防止最后一个节点也是重复 将最后一个不重复的节点置为空tmp.next = null;return newHead.next;}


MylinkedList.java
class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}
}public class MyLinkedList {public ListNode head;public void addLast(int data) {ListNode node = new ListNode(data);if (this.head == null) {this.head = node;} else {ListNode cur = this.head;while (cur.next != null) {cur = cur.next;}cur.next = node;}}public void display() {ListNode cur = this.head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}/*** 从指定头节点开始打印* @param newHead*/public void display2(ListNode newHead) {ListNode cur = newHead;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}// 反转一个单链表public ListNode reverseList() {if(this.head == null)  {return null;}ListNode prev = null;ListNode cur = this.head;while(cur != null) {ListNode curNext = cur.next;cur.next = prev;prev = cur;cur = curNext;}return prev;}//  给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点// 偶数第二个public ListNode middleNode() {if(this.head == null) {return null;}ListNode fast = this.head;ListNode slow = this.head;while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}return slow;}// 偶数第一个public ListNode middleNode1() {if(this.head == null) {return null;}ListNode fast = this.head;ListNode slow = this.head;while(fast != null && fast.next != null) {fast = fast.next.next;if(fast == null) {return slow;}slow = slow.next;}return slow;}// 输入一个链表,输出该链表中倒数第k个结点public ListNode findKthToTail(int k) {if(k < 0 || head == null) {return null;}ListNode fast = this.head;ListNode slow = this.head;while(k-1 != 0) {fast = fast.next;if(fast == null) {return null;}k--;}while(fast.next != null) {fast = fast.next;slow = slow.next;}return slow;}// 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的public ListNode mergeTwoLists(ListNode headA, ListNode headB) {ListNode newHead = new ListNode(-1);ListNode tmp = newHead;while(headA != null && headB != null) {if (headA.val < headB.val) {tmp.next = headA;headA = headA.next;tmp = tmp.next;} else {tmp.next = headB;headB = headB.next;tmp = tmp.next;}}if (headA != null) {tmp.next = headA;}if (headB != null) {tmp.next = headB;}return newHead.next;}// 以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前public ListNode partition(int x) {ListNode bs = null;ListNode be = null;ListNode as = null;ListNode ae = null;ListNode cur = this.head;while (cur != null) {if(cur.val < x) {// 第一次if(bs == null) {bs = cur;be = cur;}else {// 非首次be.next = cur;be = be.next;}}else {// 第一次if(as == null) {as = cur;ae = cur;}else {// 非首次ae.next = cur;ae = ae.next;}}cur = cur.next;}// 预防第一个段为空if(bs == null) {return as;}// 串be.next = as;// 预防第二个段中的数据 最后一个节点不是空if(as != null) {ae.next = null;}return bs;}// 删除链表重复节点public ListNode deleteDuplication() {ListNode cur = head;ListNode newHead = new ListNode(-1);ListNode tmp = newHead;while(cur != null) {if(cur.next != null && cur.val == cur.next.val) {while(cur.next != null && cur.val == cur.next.val) {cur = cur.next;}cur = cur.next;}else {tmp.next = cur;tmp = tmp.next;cur = cur.next;}}// 防止最后一个节点也是重复 将最后一个不重复的节点置为空tmp.next = null;return newHead.next;}
}
TestDemo.java
public class TestDemo {public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);MyLinkedList myLinkedList2 = new MyLinkedList();myLinkedList2.addLast(13);myLinkedList2.addLast(24);myLinkedList2.addLast(30);ListNode ret = myLinkedList.mergeTwoLists(myLinkedList.head, myLinkedList2.head);myLinkedList.display2(ret); // 12 13 23 24 30 34 45}public static void main3(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);myLinkedList.display();ListNode ret = myLinkedList.findKthToTail(3);System.out.println(ret.val); // 34}public static void main2(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.display();ListNode even = myLinkedList.middleNode(); // 偶数第二个System.out.println(even.val); // 34ListNode even2 = myLinkedList.middleNode1(); // 偶数第一个System.out.println(even2.val); // 23myLinkedList.addLast(56);ListNode odd = myLinkedList.middleNode(); // 奇数System.out.println(odd.val); // 34}public static void main1(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.display();ListNode ret = myLinkedList.reverseList();myLinkedList.display2(ret); // 56 45 34 23 12}
}

4.7、链表的回文结构

【OJ链接】

public boolean chkPalindrome() {if(head == null) return true;// 找中间节点ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}// slow走到了中间位置// 反转ListNode cur = slow.next;while(cur != null) {ListNode curNext = cur.next; // 记录cur下一个cur.next = slow;slow = cur;cur = curNext;}// 判断回文while(head != slow) {if(head.val != slow.val) {return false;}// 偶数if(head.next == slow) {return true;}head = head.next;slow = slow.next;}return true;}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(23);myLinkedList.addLast(12);System.out.println(myLinkedList.chkPalindrome()); // true}


4.8、输入两个链表,找出它们的第一个公共结点

【OJ链接】

 // 创建相交链表 测试public void createCut(ListNode headA, ListNode headB) {headA.next.next = headB.next.next;}public ListNode getIntersectionNode(ListNode headA, ListNode headB) {if(headA == null || headB == null) {return null;}ListNode pl = headA;ListNode ps = headB;int lenA = 0;int lenB = 0;while(pl != null) {lenA++;pl = pl.next;}// pl==nullpl = headA;while(ps != null) {lenB++;ps = ps.next;}// ps = nullps = headB;int len = lenA - lenB; // 差值步if(len < 0) {pl = headB;ps = headA;len = lenB - lenA;}// pl永远指向了最长的链表 ps永远指向了最短的链表 求了差值步len// 较长的链表 pl 走差值步while(len != 0) {pl = pl.next;len--;}// 同时走 直到相遇while(pl != ps) {pl = pl.next;ps = ps.next;}return pl; // 如果为空 直接返回就可}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);MyLinkedList myLinkedList1 = new MyLinkedList();myLinkedList1.addLast(13);myLinkedList1.addLast(23);myLinkedList1.addLast(30);myLinkedList.createCut(myLinkedList.head, myLinkedList1.head);ListNode ret = myLinkedList.getIntersectionNode(myLinkedList.head, myLinkedList1.head);System.out.println(ret.val); // 30}


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

【OJ链接】

 public boolean hasCycle() {if(head == null) return false;ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null) {fast = fast .next.next;slow = slow.next;if(fast == slow) {return true;}}return false;}public boolean hasCycle2() {if(head == null) return false;ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null) {fast = fast .next.next;slow = slow.next;if(fast == slow) {break;}}if(fast == null || fast.next == null) {return false;}return true;}// 构建一个环public void creatLoop() {ListNode cur = this.head;while(cur.next != null) {cur = cur.next;}cur.next = head.next.next;}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);myLinkedList.addLast(23);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addLast(56);myLinkedList.creatLoop();System.out.println(myLinkedList.hasCycle()); // true}


4.10、给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

【OJ链接】

 public ListNode detectCycle() {// 判断是否有环if(head == null) return null;ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null) {fast = fast .next.next;slow = slow.next;if(fast == slow) {break;}}if(fast == null || fast.next == null) {return null;}// 返回入口点fast = head;while(fast != slow) {fast = fast.next;slow = slow.next;}return fast;}


4.11、选择题


5、无头双向链表增删查改

MylinkedList.java

class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}
}public class MyLinkedList {public ListNode head; // 指向双向链表的头节点public ListNode last; // 指向的是尾巴节点public void display() {// 和单链表的打印方式是一样的ListNode cur = this.head;while(cur != null) {System.out.print(cur.val+" ");cur = cur.next;}System.out.println();}// 得到单链表的长度public int size() {int cnt = 0;ListNode cur = this.head;while(cur != null) {cnt++;cur = cur.next;}return cnt;}// 查找是否包含关键字key是否在单链表当中public boolean contains(int key){ListNode cur = this.head;while(cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;}// 头插法public void addFirst(int data) {ListNode node = new ListNode(data);if(this.head == null) {this.head = node;this.last = node;}else {node.next = this.head;this.head.prev = node;this.head = node;}}// 尾插法public void addLast(int data){ListNode node = new ListNode(data);if(this.head == null) {head = node;last = node;}else {this.last.next = node;node.prev = this.last;this.last = node;}}public ListNode searchIndex(int index) {// 返回index位置的地址ListNode cur = this.head;while(index != 0) {cur = cur.next;index--;}return cur;}// 任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data){ListNode node = new ListNode(data);if(index < 0 || index > size()) {System.out.println("index 位置不合法");return;}// 头插if(index == 0) {addFirst(data);return;}// 尾插if(index == size()) {addLast(data);return;}// 中间ListNode cur = searchIndex(index);node.next = cur;node.prev = cur.prev;cur.prev.next = node;cur.prev = node;}// 删除第一次出现关键字为key的节点public void remove(int key){ListNode cur = this.head;while(cur != null) {if(cur.val == key) {if(cur == this.head) {this.head = head.next;if(this.head != null) { //this.head.prev = null;}else {this.last = null;}}else if(cur == this.last){this.last = this.last.prev;this.last.next = null;}else {cur.prev.next = cur.next;cur.next.prev = cur.prev;}return;}cur = cur.next;}}public void remove1(int key){ListNode cur = this.head;while(cur != null) {if(cur.val == key) {if(cur == this.head) {this.head = head.next;if(this.head != null) { //this.head.prev = null;}else {this.last = null;}}else {cur.prev.next = cur.next;if(cur.next != null) {// 中间位置cur.next.prev = cur.prev;}else {this.last = this.last.prev;}}return;}cur = cur.next;}}// 删除所有值为key的节点public void removeAllKey(int key){ListNode cur = this.head;while(cur != null) {if(cur.val == key) {if(cur == this.head) {this.head = head.next;if(this.head != null) { //this.head.prev = null;}else {this.last = null;}}else if(cur == this.last){this.last = this.last.prev;this.last.next = null;}else {cur.prev.next = cur.next;cur.next.prev = cur.prev;}// return;}cur = cur.next;}}public void clear() {while(this.head != null) {ListNode curNext = this.head.next;this.head.next = null;this.head.prev = null;this.head = curNext;}this.last = null;/*ListNode cur = this.head;while(cur != null) {ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}this.head = null;this.last = null;*/}
}

TestDemo.java
public class TestDemo {public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(1);myLinkedList.addLast(2);myLinkedList.addLast(2);myLinkedList.addLast(2);myLinkedList.addLast(3);myLinkedList.display(); // 1 2 2 2 3myLinkedList.remove(1);myLinkedList.display(); // 2 2 2 3// myLinkedList.removeAllKey(2);// myLinkedList.display(); // 3myLinkedList.addIndex(0, 99);myLinkedList.display(); // 99 2 2 2 3myLinkedList.addIndex(5, 99);myLinkedList.display(); // 99 2 2 2 3 99myLinkedList.addIndex(3, 99);myLinkedList.display(); // 99 2 2 99 2 3 99}public static void main1(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(1);myLinkedList.addFirst(2);myLinkedList.addFirst(3);myLinkedList.addFirst(4);System.out.println(myLinkedList.size()); // 4System.out.println(myLinkedList.contains(1)); // truemyLinkedList.display(); // 4 3 2 1myLinkedList.addLast(11);myLinkedList.addLast(12);myLinkedList.display(); // 4 3 2 1 11 12}
}

6、实现双向链表(带傀儡节点)

MylinkedList.java
class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}
}public class MyLinkedList {public ListNode head = new ListNode(-1);public ListNode last;// 打印public void display() {ListNode cur = this.head.next; //while(cur != null) {System.out.print(cur.val+" ");cur = cur.next;}System.out.println();}// 得到单链表的长度public int size() {ListNode cur = this.head.next; //int cnt = 0;while(cur != null) {cnt++;cur = cur.next;}return cnt;}// 查找是否包含关键字key是否在单链表当中public boolean contains(int key){ListNode cur = this.head.next;while(cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;}// 头插法public void addFirst(int data) {ListNode node = new ListNode(data);if(this.head.next == null) {this.head.next = node;node.prev = this.head;this.last = node;} else {node.next = this.head.next;node.next.prev = node;node.prev = this.head;this.head.next = node;}}// 尾插法public void addLast(int data){ListNode node = new ListNode(data);if(this.head.next == null) {this.head.next = node;node.prev = this.head;this.last = node;} else {this.last.next = node;node.prev = last;this.last = node;}}public ListNode searchIndex(int index) {ListNode cur = this.head;while(index != 0) {cur = cur.next;index--;}return cur;}// 任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data){if(index < 0 || index > size()) {System.out.println("index 下标范围错误");return;}if(index == 0) {addFirst(data);} else if(index == size()) {addLast(data);} else {ListNode node = new ListNode(data);ListNode cur = searchIndex(index);node.next = cur;node.prev = cur.prev;cur.prev.next = node;cur.prev = node;}}// 删除第一次出现关键字为key的节点public void remove(int key){ListNode cur = this.head.next;while(cur != null) {if(cur.val == key) {if(cur == this.head.next) {this.head.next = cur.next;cur.next.prev = this.head;} else if (cur == this.last) {this.last = this.last.prev;this.last.next = null;} else {cur.prev.next = cur.next;cur.next.prev = cur.prev;}return;}cur = cur.next;}}// 删除所有值为key的节点public void removeAllKey(int key){ListNode cur = this.head.next;while(cur != null) {if(cur.val == key) {if(cur == this.head.next) {this.head.next = cur.next;cur.next.prev = this.head;} else if (cur == this.last) {this.last = this.last.prev;this.last.next = null;} else {cur.prev.next = cur.next;cur.next.prev = cur.prev;}}cur = cur.next;}}// 清空public void clear() {ListNode cur = this.head.next;while(cur != null) {ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}this.head = null;this.last = null;}
}


三、总结

问题:
1.顺序表和链表的区别?
2.数组和链表的区别?
3.ArrayList和LinkedList的区别?

共同点:对数据的组织方式和描述方法不同

组织:
1.顺序表底层是一个数组,逻辑上和物理上都是连续
2.链表是一个由若干节点组成的数据结构,逻辑上连续的,但在物理上/内存上 不一定连续
操作:
1.顺序表适合查找相关的操作,因为可以使用下标,直接获取到某个位置的元素
2.链表适合频繁地插入删除操作,不需要像顺序表一样移动元素。链表的插入,只需要修改指向
3.顺序表满了需要扩容,扩容后不一定都能放完,所以空间上的利用率不高

【顺序表和链表】实现增删查改数据结构 OJ题编程相关推荐

  1. 数据结构之单链表的增删查改等操作画图详解

    单链表 文章目录 单链表 链表的概念及其结构 概念 结构 链表的实现 开辟一个新结点 链表的销毁 打印链表 单链表的尾插 单链表的头插 单链表的头删 单链表的尾删 找到单链表中的一个结点 在pos位置 ...

  2. Java——链表的增删查改

    [基础学习] 链表的增删查改 注意:所有链表都先需要判断是否为null <1>链表的增 有三种方法,分别为:头插法,尾插法,任意节点位置插法 1.头插法 2.尾插法 3.任意节点位置插法 ...

  3. c语言 单链表的增删查改

    文章目录 1.链表基本结构 2.链表的尾插 3.链表的尾删 4.链表的头插与头删 头插 头删 5.链表的查找与修改 查找 修改 6.链表的节点插入与删除 插入 删除 1.链表基本结构 链表由一个个的节 ...

  4. Django:数据库表的建立与增删查改(ForeignKey和ManytoMany)

    数据库表的创建: 1.Django工程项目建立,基础环境调试. 2.创建表 from django.db import models class Publisher(models.Model):    ...

  5. 单链表的增删查改等基本操作C++实现

    单链表的初始化.增删查改.遍历一次找中间结点.删除一个无头单链表的非尾结点(不给头结点) #include<stdio.h> #include<stdlib.h> #inclu ...

  6. MySQL第二讲 - 数据表简单操作 与 “增删查改的开头部分- 增”- 细节狂魔

    文章目录 前文知识点回顾   SQL语句 >>操作指令 (不区分大小写) 1.显示数据库:show databases; 2.创建数据库:create database 数据库名; [如果 ...

  7. 【数据结构】单链表的增删查改(C语言实现)

    文章目录 前言 一.链表 1.链表的概念及结构 2.链表的分类 3.最常用的两种链表 二.单链表的实现 1.结构的定义 2.创建新节点 3.在头部插入数据 4.在尾部插入数据 5.查找数据 6.在po ...

  8. C语言 数据结构 链表的增删查改

    分别用函数实现了链表的: 1.增加(头插法,尾插法,有序插入) 2.删除 3.修改 4.查找 C代码 #define _CRT_SECURE_NO_WARNINGS #include<stdio ...

  9. MySQL~数据库表中数据的增删查改(基础篇)

    文章目录 增加 建表 多行数据 全列插入 多行数据 指定列插入 查询 全列查询 指定列查询 查询字段为表达式 查询字段 名字重定义 去重 distinct 排序 order by 条件查询 运算符 比 ...

最新文章

  1. 适合新手练手,用Python爬取OPGG里英雄联盟英雄胜率及选取率,详细讲解加注释(建议收藏练手)
  2. android - Animation详解
  3. 東方茸回廊 汉化补丁
  4. 关于自动寻径和图、邻接表的学习和启发
  5. Perturbed Masking:和参数无关的预训练模型分析方法
  6. 删库了,我们一定要跑路吗?
  7. python简述文件目录相对路径_【Python】 配置文件相对路径软件自动执行的工作目录...
  8. 手机价格要上涨?小米和Realme确认芯片短缺:高通交付延长至30周以上
  9. Linux shell 字符串转数字进行运算符操作
  10. [转载] 七龙珠第一部——第009话 兔子头儿的绝招
  11. 【NCRE】——Winform窗体控件随窗体大小而变化
  12. office, pdf, cad 等在线预览
  13. 大数据-数据仓库的概念
  14. LaTeX新手入门以及TeXlive和TeXstudio的安装使用
  15. 短视频运营小技巧,掌握推荐机制很重要,吸粉引流也不难
  16. easyui事件方法onChange()、onSelect()、 onLoadSuccess()
  17. 网上做什么可以赚钱?网上最靠谱的赚钱方法
  18. java计算机毕业设计会议查询系统源程序+mysql+系统+lw文档+远程调试
  19. ASCII与Unicode编码消息写文件浅析
  20. HDu--我要拿走你的蜡烛

热门文章

  1. Linux 配置vim编辑器
  2. 您企业的邮件系统够安全吗
  3. 找回被删并清空了回收站的文件
  4. 国内专业移动广告聚合平台,KeyMob,手机广告效果最棒
  5. Maven实战读书笔记(3)
  6. SQL中Case语句用法讨论
  7. Laravel-数据库队列
  8. 算法-lowb三人组
  9. 拒绝礼仪与技巧(转)
  10. dd大牛《背包九讲》(转载)