本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/68
数据结构和算法-单向链表
链表是线性表的链式存储方式,逻辑上相邻的数据在计算机内的存储位置不必须相邻,那么,怎么表示逻辑上的相邻关系呢?可以给每个元素附加一个指针域,指向下一个元素的存储位置。 如图:
从上图中我们也可以直观看出,每个结点包含两个域:数据域和指针域,指针域存储下一个结点的地址,因此指针指向的类型也是结点类型。
单向链表
双向链表
循环链表
链表中最简单的一种是单向链表,它包含两个域,一个信息域(data)和一个指针域(next)。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值(NULL)。所谓单链表无疑是链式存储方式,节点中的next指针指向下一个节点,存储空间不是连续的。
单向链表我们把他分为头节点和节点,头节点默认是链表的头部,不存储数据,节点则存储数据。
如图,头节点不存储数据,但是他的指针指向节点1的地址,所以头节点和节点1链接起来了。然后节点1的指针又指向了节点2的地址,使节点1和节点2也链接起来了…最后,节点i的指针指向节点n,最后一个节点,最后一个节点n的指针指向了NULL。至此,一条链条诞生了。
单向链表的操作
单向链表的操作方式主要分为增、删、改、查等操作
(1)若原链表为空,则将新建节点设置为头节点
(2)若原链表为非空,则将新建节点添加到表尾
向一个链表中插入一个新节点时,首先要新建一个节点,并将新建节点的指针域初始化为空NULL,然后在链表中寻找适当的位置执行节点插入操作,此时需要考虑下面4种情况:
(1)若原链表为空,则将新建节点p作为头节点,让head指向新节点p
(2)若原链表为非空,折按新建节点的值的大小(假设原链表已按节点值升序排列)确定插入新节点的位置。若在头结点前插入新节点,则将新节点的指针域指向原链表的头结点,并且让head指向新节点p
(3)若在原链表中间插入新节点,则将新节点p的指针域指向下一节点,并且让前一节点的指针域指向新建节点p
(4)若在表尾插入新节点,则将尾节点的指针域指向新节点p
链表的删除操作就是将待删除的节点从链表中断开,那么待删除节点的上一个节点就成为尾节点。在删除节点时,我们要考虑一下4种情况:
(1)若原链表为空,则不执行任何操作,直接退出程序
(2)若待删除节点是头节点,则将head指向当前节点的下一个节点,再删除当前节点
(3)若待删除节点不是头节点,则将前一节点的指针域指向当前节点的下一节点,即可删除当前节点。当待删除节点是尾节点时,由于p->next=NULL,因此执行pr->next = p->next后,pr->next的值也变为了NULL,从而使pr所指向的节点由倒数第二个节点变成尾节点。
(4)若待删除的节点不存在,则退出程序
注意:节点被删除后,只表示将它从链表中断开而已,它仍占用着内存,必须要释放这个内存,否则会出现内存泄漏。
(1)若原链表为空,则不执行任何操作,直接退出程序
(2)若节点找到,对节点数据进行修改,否则直到节点未找到时,则退出程序
(1)若原链表为空,则不执行任何操作,直接退出程序
(2)若节点找到,则返回节点,否则直到节点未找到时,则退出程序
package com.joshua317; public class Main { public static void main(String[] args) { // write your code here Node node1 = new Node(1,"小松"); Node node2 = new Node(2,"小明"); Node node3 = new Node(3,"小红"); SingleLinkedList singleLinkedList = new SingleLinkedList(); singleLinkedList.add(node1); singleLinkedList.add(node2); singleLinkedList.add(node3); singleLinkedList.list(); singleLinkedList.len(); singleLinkedList.delete(4); System.out.println("删除节点后的列表为:"); singleLinkedList.list(); } } class SingleLinkedList { //先初始化一个头节点 private Node head = new Node(0, ""); /** * 添加节点到单向链表,不考虑排序,在链表尾部加入节点 * 1.找到当前链表的最后节点 * 2.将最后这个节点的next指向新的节点 */ public void add(Node node) { Node temp = head; //遍历链表,找到最后的节点 while (true) { if (temp.next == null) { break; } temp = temp.next; } //当退出while循环时,temp就指向了链表的最后 //将最后temp节点的next指向新的节点 temp.next = node; } //显示链表[遍历] public void list() { //判断链表是否为空 if (head.next == null) { System.out.println("链表为空"); return; } //因为头节点不能动,所以需要一个辅助变量来遍历 Node temp = head.next; while (true) { //判断节点是否为空 if (temp == null) { break; } System.out.println(temp); temp = temp.next; } } /** * 获取节点数据 * @param no */ public void get(int no) { //判断链表是否为空 if (head.next == null) { System.out.println("链表为空"); return; } //因为头节点不能动,所以需要一个辅助变量来遍历 Node temp = head.next; while (true) { if (temp == null) { break; } if (temp.no == no) { System.out.println(temp); break; } temp = temp.next; } } public void delete(int no) { //判断链表是否为空 if (head.next == null) { System.out.println("链表为空"); return; } //因为头节点不能动,所以需要一个辅助变量来遍历 Node temp = head; boolean flag = false; while (true) { if (temp.next == null) { break; } if (temp.next.no == no) { flag = true; break; } temp = temp.next; } if (flag) { temp.next = temp.next.next; } else { System.out.println("数据no:" + no + "不存在"); } } public int len() { //判断链表是否为空 if (head.next == null) { System.out.println("链表为空"); return 0; } Node temp = head.next; int len = 0; while (true) { if (temp == null) { break; } len++; temp = temp.next; } System.out.println("链表的长度为:" + len); return len; } } //定义一个Node节点,每个Node对象是一个节点 class Node { public int no; public String name; public Node next;//指向下一个节点 //构造函数 public Node (int no, String name) { this.no = no; this.name = name; } @Override public String toString() { return "Node{" + "no=" + no + ", name='" + name + '\'' + '}'; } }
5.1 两数相加
5.2 判断链表中是否有环
5.3 删除链表的倒数第N个节点
5.4 反转链表(单链表)
5.5 回文链表
5.6 合并两个有序链表
本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/68