《算法导论》学习笔记之Chapter10---数据结构之链表

2024-05-16 00:18

本文主要是介绍《算法导论》学习笔记之Chapter10---数据结构之链表,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

链表定义:链表是这样一种数据结构,其中的各对象按线性顺序排列,与数组的线性顺序由下标决定不同,链表的顺序是由各个对象里的指针决定。

链表分为:单向链表,双向链表,还有循环链表。

链表支持的操作有:查找Search;插入Insert;删除Delete;

双向链表的查找操作就是从表头开始对比查找,很简单;插入操作,是根据插入的数据的指针属性来寻找要插入的位置;之后修改相关元素的pre和next指针属性即可;删除操作与插入操作类似,只是在找到要删除的元素的位置之后,直接将该元素前一个节点的next属性设置为被删除节点的next属性值,将被删除节点后面的节点的pre属性值设置为被删除节点的pre属性值即可。可以自行画图来加深理解。而在链表中,有一个重要的定义就是-节点,前面所说的元素值,pre,next属性都应该包含在节点里面的。

注意,链表的查找,删除操作其实都是可以分为按照内容的操作和按照指针的操作的。

本文,介绍单向链表和双向链表的几种java实现。

下面是单向链表的基本操作的代码实现:

import java.util.List;public class LinkedListTest {Node head = null;// 链表头/*** 向链表中插入数据* * @param args*/public void insert(int d) {Node newNode = new Node(d);// 将要插入的数据包装成链表的节点// 如果链表为空,则将要插入节点作为头节点if (head == null) {head = newNode;return;}// 下面代码是寻找链表的尾节点Node tmp = head;while (tmp.next != null) {tmp = tmp.next;}// 将新节点插入大奥为节点的后面tmp.next = newNode;}// 删除第i个节点public boolean deletaNode(int i) {// 如果删除的位置不合理,则返回falseif (i < 1 && i > length()) {return false;}// 删除的是链表的头结点if (i == 1) {head = head.next;return true;}// 删除的是链表的中间节点int j = 2;Node preNode = head;Node curNode = preNode.next;while (curNode != null) {if (j == i) {preNode.next = curNode.next;return true;}preNode = curNode;curNode = curNode.next;j++;}return true;}// 返回链表的长度public int length() {int length = 0;Node tmp = head;while (tmp != null) {tmp = tmp.next;length++;}return length;}// 链表排序,返回排序后的头节点public Node sortList() {Node nextNode = null;int tmp = 0;Node curNode = head;// 采用冒泡排序的方法对链表数据进行排序while (curNode.next != null) {nextNode = curNode.next;while (nextNode != null) {if (curNode.data > nextNode.data) {tmp = curNode.data;curNode.data = nextNode.data;nextNode.data = tmp;}nextNode = nextNode.next;}curNode = curNode.next;}return head;}// 打印链表public void printList() {Node tmp = head;while (tmp != null) {System.out.println(tmp.data);tmp = tmp.next;}}public static void main(String[] args) {// TODO Auto-generated method stubLinkedListTest list = new LinkedListTest();list.insert(5);list.insert(1);list.insert(4);list.insert(3);list.insert(2);System.out.println(list.length());list.printList();list.sortList();list.printList();list.deletaNode(1);list.printList();list.deletaNode(3);list.printList();}}// 定义链表的节点类型
class Node {int data;Node next = null;public Node(int data) {this.data = data;}
}

下面介绍单链表中的删除重复数据的方法:

/*** 删除重复数据 方法1时间复杂度小,但是需要额外的存储空间 方法2时间复杂度高,但是不需要额外的存储空间* * @param head*/public void deleteDuplecate1(Node head) {Hashtable<Integer, Integer> table = new Hashtable<Integer, Integer>();Node tmp = head;Node pre = null;while (tmp != null) {if (table.containsKey(tmp.data)) {pre.next = tmp.next;} else {table.put(tmp.data, 1);pre = tmp;}tmp = tmp.next;}}public void deleteDuplecate2(Node head) {Node tmp = head;while (tmp != null) {Node cur = head;Node pre = null;while (cur != tmp) {if (cur.data == tmp.data) {pre.next = cur.next;break;} else {pre = cur;cur = cur.next;}}tmp = tmp.next;}tmp = tmp.next;}

寻找链表中倒数第k个节点:

//如何找到链表中倒数第k个节点,重点在倒数public Node find(Node head, int k){if( k < 1 || k > this.length()){return null;}Node p1 = head;Node p2 = head;//将p1指针向后先移动k个位置,这样当P1移动到结尾时,p2的位置就是倒数第kfor(int i = 0; i < k - 1; i++){p1 = p1.next;}while(p1 != null){p1 = p1.next;p2 = p2.next;}return p2;}

实现链表的反转(非递归实现):

// 链表反转非递归实现public void reverse(Node head) {Node pRevereHead = head;Node pNode = head;Node pPre = null;while (pNode != null) {// pNext用来记录下一个节点,防止pNode的next节点转向之后,与后面的节点断开联系Node pNext = pNode.next;if (pNext == null) {pRevereHead = pNode;}pNode.next = pPre;pPre = pNode;pNode = pNext;}this.head = pRevereHead;}

下面还有关于单向链表的好几种操作,在此我就只记录一下这几个操作的思想吧:

从链表尾部开始输出节点:使用递归,每访问到一个节点,先递归输出后面的节点,再输出该节点自身。

访问链表中间节点:是用两个指针,一个指针单步移动,一个指针双步移动,当双步指针移动到链表尾部,则单步指针指向的节点为链表中间节点。

如何判断两个链表是否相交:如果链表相交,则一定有相同的尾节点。



这篇关于《算法导论》学习笔记之Chapter10---数据结构之链表的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/993333

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

csu1329(双向链表)

题意:给n个盒子,编号为1到n,四个操作:1、将x盒子移到y的左边;2、将x盒子移到y的右边;3、交换x和y盒子的位置;4、将所有的盒子反过来放。 思路分析:用双向链表解决。每个操作的时间复杂度为O(1),用数组来模拟链表,下面的代码是参考刘老师的标程写的。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#