Structure de données Java, liste chaînée unique et questions JO
Cet article vous apporte des connaissances pertinentes sur java. Il présente principalement le contenu pertinent sur la structure des données, y compris les listes à lien unique et les questions JO. J'espère qu'il sera utile à tout le monde.
Apprentissage recommandé : "Tutoriel vidéo Java"
1.
Une liste chaînée est une structure de stockage physique non continue. L'ordre logique des éléments de données est obtenu grâce à l'ordre des liens de référence dans la liste chaînée.
En termes simples, chaque élément est un nœud et un champ de pointeur est utilisé pour connecter les nœuds suivants. Le premier nœud n'a pas de prédécesseur et le dernier nœud n'a pas de successeur.
Les structures de listes chaînées à mettre en œuvre dans la pratique sont très diverses. Il existe 8 types de structures de listes chaînées lorsqu'elles sont combinées avec les situations suivantes :
1. , pas en tête 3. Cyclique, non cyclique
Nous nous concentrons sur l'explication des listes chaînées acycliques unidirectionnelles et des listes chaînées acycliques bidirectionnelles. En même temps, ces deux-là sont également testées plus fréquemment lors de l'examen écrit.
2. Implémenter une liste chaînée acyclique unidirectionnelle
2.1 Accord avant la mise en œuvre
Parce que chaque élément de la liste chaînée est un nœud, nous adoptons la méthode de classe interne et nous devons également définir une tête node La référence pointe toujours vers le nœud principal.
public class MySingleList { private ListNode head; //引用头节点 // 链表每个元素是一个节点 private class ListNode { private int val; //存放数据元素 private ListNode next; //存放下一个节点地址 //构造方法 public ListNode(int val) { this.val = val; } } }
Remarque : une liste chaînée comporte au moins deux champs, à savoir un champ de données et un champ de pointeur. Bien sûr, vous pouvez également avoir plusieurs champs de données et champs de pointeur.
Nous devons également implémenter les méthodes courantes suivantes :
public void addFirst(int data); //头插法 public void addLast(int data); //尾插法 public boolean addIndex(int index,int data); //任意位置插入,第一个数据节点为0号下标 public boolean contains(int key); //查找关键字key是否在单链表当中 public void remove(int key); //删除第一次出现关键字为key的节点 public void removeAllKey(int key); //删除所有值为key的节点 public int size(); //得到单链表的长度 public void clear(); //清空链表
2.2 méthode addFirst
public void addFirst(int data) { ListNode newNode = new ListNode(data); //把传过来的值放到新的节点中 newNode.next = this.head; //新节点的next指向头节点 this.head = newNode; //使新节点成为头节点 }
Parce que head pointe vers vide par défaut, lorsque la liste chaînée est nulle, cela n'affectera pas l'exécution de ce code If. tu ne me crois pas, viens le dessiner.
2.3 méthode addList
public void addLast(int data) { ListNode newNode = new ListNode(data); // 如果链表为空的情况 if (this.head == null) { this.head = newNode; return; } // 先找到最后一个节点 ListNode cur = this.head; while (cur.next != null) { cur = cur.next; } cur.next = newNode; }
2.4 méthode addIndex
//任意位置插入,第一个数据节点为0号下标 private ListNode findIndexPrevNode(int index) { ListNode cur = this.head; while (index - 1 != 0) { cur = cur.next; index--; } return cur; } public boolean addIndex(int index,int data) { // 判断index下标的有效性 if (index < 0 || index > size()) { return false; } // 如果在0下标插入则是头插 if (index == 0) { addFirst(data); //头插 return true; } // 如果在末尾插入则是尾插 if (index == size()) { addLast(data); //尾插 return true; } ListNode newNode = new ListNode(data); //新节点 // 在中间插入 ListNode prevNode = findIndexPrevNode(index); //找到index下标的前一个节点 newNode.next = prevNode.next; //新节点的next被改为index的位置的节点 prevNode.next = newNode; //index位置前一个节点next被改成新节点 return true; }
Dans ce code, nous devons d'abord trouver le nœud précédent de l'indice d'index, lier d'abord le nouveau nœud au nœud à la position d'index, puis lier le nœud précédent de l'index Le nœud est connecté au nouveau nœud. Le texte ici n'est pas clair. Les amis peuvent descendre et dessiner des images selon mon code pour comprendre. Vous pouvez également lire directement la colonne précédente du blogueur sur l'implémentation du langage C. de la structure des données. Il existe des illustrations.
2.5 contient la méthode
//查找关键字key是否在单链表当中 public boolean contains(int key) { // 当链表为空的情况 if (this.head == null) { return false; } ListNode cur = this.head; // 遍历列表 while (cur != null) { if (cur.val == key) { return true; //找到了返回true } cur = cur.next; } return false; //找不到返回false }
L'idée est très simple, parcourez la liste chaînée et trouvez la position où cur est vide, si vrai est renvoyé, si faux n'est pas renvoyé, laissez vos amis faire le dessin.
Méthode de suppression 2.6
//删除第一次出现关键字为key的节点 public void remove(int key) { if (this.head == null) { return; } ListNode cur = this.head; // 如果删除的是key为头节点 if (this.head.val == key) { this.head = head.next; return; } // 这里不能是cur!=null, 不然会越界!!! while (cur.next != null) { // 找到 key 的前一个节点 if (cur.next.val == key) { //当前的cur为key的前一个节点 cur.next = cur.next.next; //cur链接到key的后一个节点 return; } cur = cur.next; } }
Ici, nous devons trouver le nœud précédent de la clé, puis le lier au nœud derrière la clé. Lorsque le nœud correspondant à la clé n'est plus référencé, il sera automatiquement recyclé. .
2.7 Méthode RemoveAllKey
//删除所有值为key的节点 public void removeAllKey(int key) { if (this.head == null) { return; } // 采用前后指针的方法 ListNode cur = this.head; ListNode prev = this.head; while (cur != null) { if (cur.val == key) { prev.next = cur.next; //跳过key节点指向下一个节点 } else { prev = cur; } cur = cur.next; } // 判断第一个节点是不是key if (this.head.val == key) { this.head = this.head.next; //head指向下一个节点 } }
Examinons-la d'abord vous-même. Cette question sera expliquée en détail plus tard lorsque nous expliquerons la question JO.
Taille 2,8 et méthode claire
Je pense que ces deux méthodes n'ont pas besoin d'être dites beaucoup, n'est-ce pas ? Traverser? Définir directement le pointeur de tête sur null ? N'est-ce pas simple ? Je ne l'écrirai pas ici, je vous le laisse !
3. Anatomie approfondie de la question JO de liste chaînée unique
C'est le point culminant d'aujourd'hui. Ce n'est pas que le basketteur ne dessine pas d'images, c'est parce que les images précédentes sont trop simples. par eux-mêmes en combinant le code, mais, pour les questions JO, vous devez toujours faire des dessins. Je pense qu'après avoir lu ces questions, vous tomberez amoureux des structures de données.
3.1 Supprimer les éléments d'une liste chaînée (Source : LeetCode Difficulté : Facile)
Question : Donnez-vous le nœud principal d'une liste chaînée
head
和一个整数val
,请你删除链表中所有满足Node.val == val
et renvoyez le nouveau nœud principal.
这个题我们可以用前后指针的思路来做,这样也比较通俗易懂,更适合初学者,大概的思路是这样的:我们可以定义一个cur和first的引用,如果碰到相等,也就是first.val == val,我们则让cur的next指向first的下一个节点,如果不相等,则让cur走到first的位置,最后first往后走一步,图解:
这里还没有完,如果第一个节点的值也是val呢?所以最后我们别忘了进行一个判断,那么最终的代码是这样的:
public ListNode removeElements(ListNode head, int val) { if (head == null) { return null; } ListNode cur = head; ListNode first = head; while (first != null) { if (first.val == val) { cur.next = first.next; } else { cur = first; } first = first.next; } // 判断头节点的值是否也是val if (head.val == val) { head = head.next; } return head; }
3.2 反转链表(来源:LeetCode 难度:简单)
题目:给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。
这个题我们可以先取到头节点,后续的节点都进行头插法即可?我们取到头节点,并且先将头节点的next置空,但是这样一来,就找不到后面的节点了,所以我们还需要有一个curNext引用来记录要反转节点的下一个节点:
我们的思路是这样的:首先找到头节点的next置空,cur走到curNext位置,curNext往前走,使得cur位置的next指向头节点,头节点cur再次成为新的头节点,当curNext走到null的时候循环结束。
public ListNode reverseList(ListNode head) { // 空链表的情况 if (head == null) { return null; } ListNode cur = head; ListNode curNext = cur.next; head.next = null; while (curNext != null) { cur = curNext; curNext = curNext.next; cur.next = head; head = cur; } return head; }
3.4 链表中倒数第k个节点
题目:输入一个链表,输出该链表中倒数第k个结点。
这个题也是很简单的一道题,可以采用前后指针法,先让first指针走k步,走完之后slow和first一起走,这样slow和first之间就相差了k步,当first为null时,slow就是倒数第k个节点,在这个过程中,我们还要判断k的合法性,如果k小于等于0?或者k大于链表的长度呢?于是我们就能写出如下的代码:
public ListNode FindKthToTail(ListNode head,int k) { // 判断k的合法性 if (k <= 0 || head == null) { return null; } ListNode first = head; ListNode slow = head; // 先让first走k步 while (k != 0) { // k的长度大于链表的长度 if (first == null) { return null; } first = first.next; k--; } // 一起走,当first为null,slow就是倒数第k个节点 while (first != null) { first = first.next; slow = slow.next; } return slow; }
3.6 链表分割(来源:牛客网 难度:较难)
题目:现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
这个题的思路我们可以这样做,既然是按照给定的值x进行分割,那么我们设定两个盘子,盘子A放小于x的节点,盘子B放大于x的节点,最后把这两个盘子的节点连起来,放回盘子A的头节点即可!
public ListNode partition(ListNode pHead, int x) { if (pHead == null) { return null; } ListNode headA = null; ListNode headB = null; ListNode curA = null; ListNode curB = null; ListNode cur = pHead; while (cur != null) { if (cur.val < x) { // 第一次放入A盘子 if (headA == null) { headA = cur; curA = cur; } else { curA.next = cur; curA = cur; } } else { // 第一次放入B盘子 if (headB == null) { headB = cur; curB = cur; } else { curB.next = cur; curB = cur; } } cur = cur.next; } // 如果A盘子为空 if (headA == null) { return headB; } curA.next = headB; // 避免B盘子尾节点形成环 if (headB != null) { curB.next = null; } return headA; }
3.7 链表的回文结构(来源:LeetCode 难度:较难)
题目:对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
这个题有要求的,要求空间复杂度为O(1),并且还得在O(n)的时间复杂度下,那我们就原地解决这个题,我们可以分为三个步骤,首先找到中间节点,然后把中间节点往后的节点进行反转,最后左右两个指针同时往中间走。如果光看下面代码看不懂,可以结合着代码画图才能理解更透彻哦!
public boolean chkPalindrome(ListNode A) { if (A == null) { return false; } // 只有一个节点的情况 if (A.next == null) { return true; } // 首先找到中间节点 ListNode first = A; ListNode slow = A; while (first != null && first.next != null) { first = first.next.next; slow = slow.next; } // 走到这,slow是链表的中间节点,采用头插法反转slow后续的节点 first = slow.next; ListNode cur = slow; while (first != null) { cur = first; first = first.next; cur.next = slow; //链接前一个节点 slow = cur; //更新头节点的位置 } // 走到这,反转完毕,cur指向最后一个节点,让slow等于A,往中间找 slow = A; while (slow != cur) { if (slow.val != cur.val) { return false; } // 偶数的情况下需要特殊判断 if (slow.next == cur) { return true; } slow = slow.next; cur = cur.next; } return true; }
3.8 相交链表(来源:LeetCode 难度:简单)
题目:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
这个题我们可以这样做,长链表先走两个链表的长度差的步数,因为相交之后的节点都是一样的个数,所以走了差值后,就两个链表一起往后走,相等了则就是相交节点。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) { return null; } ListNode longList = headA; //longList始终记录长的链表 ListNode shortList = headB; // 分别求出两个链表的长度 int lenA = 0; int lenB = 0; ListNode cur = headA; while (cur != null) { lenA++; cur = cur.next; } cur = headB; while (cur != null) { lenB++; cur = cur.next; } int len = lenA - lenB; // 如果B链表长于A链表 if (len < 0) { // 修正相差长度 len = lenB - lenA; longList = headB; //longList始终记录长的链表 shortList = headA; } // 让长链表先走差值len步,然后同步走,相等了即为相交节点 while (len != 0) { longList = longList.next; len--; } while (longList != shortList) { longList = longList.next; shortList = shortList.next; } // 如果两个链表走到了null,则没有中间节点返回null,如果有,返回任意一个即可 return longList; }
推荐学习:《java视频教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.

Les capsules sont des figures géométriques tridimensionnelles, composées d'un cylindre et d'un hémisphère aux deux extrémités. Le volume de la capsule peut être calculé en ajoutant le volume du cylindre et le volume de l'hémisphère aux deux extrémités. Ce tutoriel discutera de la façon de calculer le volume d'une capsule donnée en Java en utilisant différentes méthodes. Formule de volume de capsule La formule du volume de la capsule est la suivante: Volume de capsule = volume cylindrique volume de deux hémisphères volume dans, R: Le rayon de l'hémisphère. H: La hauteur du cylindre (à l'exclusion de l'hémisphère). Exemple 1 entrer Rayon = 5 unités Hauteur = 10 unités Sortir Volume = 1570,8 unités cubes expliquer Calculer le volume à l'aide de la formule: Volume = π × r2 × h (4

Java est un langage de programmation populaire qui peut être appris aussi bien par les développeurs débutants que par les développeurs expérimentés. Ce didacticiel commence par les concepts de base et progresse vers des sujets avancés. Après avoir installé le kit de développement Java, vous pouvez vous entraîner à la programmation en créant un simple programme « Hello, World ! ». Une fois que vous avez compris le code, utilisez l'invite de commande pour compiler et exécuter le programme, et « Hello, World ! » s'affichera sur la console. L'apprentissage de Java commence votre parcours de programmation et, à mesure que votre maîtrise s'approfondit, vous pouvez créer des applications plus complexes.
