Une liste chaînée est une structure de données complexe. L'interrelation entre ses données divise la liste chaînée en trois types : liste chaînée simple, liste chaînée circulaire et liste chaînée double, qui seront présentées une par une ci-dessous. Les listes chaînées sont le fondement des structures de données et constituent également des points de connaissances importants. Nous parlerons ici de la mise en œuvre des listes chaînées en Java,
Opérations de liste chaînée JAVA : listes chaînées simples et listes chaînées doubles
Parlez principalement des points suivants :
1 Introduction aux listes chaînées
2. Principes et nécessité de mise en œuvre de listes chaînées
3.
4. Exemples de tableaux à double liaison
1. Introduction aux listes chaînées
Les listes chaînées sont une structure de données couramment utilisée. Bien que les listes chaînées soient plus compliquées à sauvegarder, elles sont plus pratiques pour les requêtes et sont utilisées dans de nombreux langages informatiques. Les listes chaînées ont une variété de catégories, l'article analyse les listes chaînées simplement et les listes doublement chaînées. Les données de la liste chaînée sont comme si elles étaient connectées en série par une chaîne, et les données sont facilement accessibles.
2. Principe et nécessité de la mise en œuvre des listes chaînées
Ici, nous analysons uniquement les listes chaînées simples et les listes chaînées doubles. Le processus de mise en œuvre des listes chaînées est quelque peu compliqué, mais il apportera de nombreux avantages. Par exemple, maintenant que l'ère des achats en ligne est arrivée, les commerçants emballent généralement les marchandises dans des boîtes et écrivent les informations d'adresse lorsqu'ils les envoient en livraison express. L'entreprise de messagerie peut utiliser les informations figurant sur la boîte pour trouver l'acheteur, et les marchandises arrivent intactes. Sans la protection de la boîte, les marchandises pourraient être endommagées pendant le transport. La liste chaînée est comme la boîte sur laquelle sont écrites les informations d'adresse, qui protège non seulement les informations sur le produit, mais écrit également les informations logistiques. Il y a un nœud HEAD dans la liste chaînée, semblable à une « locomotive ». Tant que le nœud HEAD correspondant est trouvé, la liste chaînée peut être exploitée. Dans cette analyse, le nœud HEAD sert uniquement d'en-tête de données et n'enregistre pas de données valides.
Le principe de mise en œuvre d'une liste chaînée simple est tel qu'illustré dans la figure :
Le principe de mise en œuvre d'une liste chaînée double :
Trois exemples de liste chaînée unique
ICommOperate
package LinkListTest; import java.util.Map; public interface ICommOperate<T> { public boolean insertNode(T node) ; public boolean insertPosNode(int pos, T node) ; public boolean deleteNode(int pos) ; public boolean updateNode(int pos, Map<String, Object> map) ; public T getNode(int pos, Map<String, Object> map) ; public void printLink() ; }
Nœud de liste chaînée unique :
package LinkListTest; // 单连表节点 public class SNode { private String data; private SNode nextNode; public SNode() { } public SNode(String data) { this.data = data; this.nextNode = new SNode(); } public String getData() { return data; } public void setData(String data) { this.data = data; } public SNode getNextNode() { return nextNode; } public void setNextNode(SNode nextNode) { this.nextNode = nextNode; } @Override public String toString() { return "SNode [data=" + data + "]"; } }
Classe d'opération à lien unique :
package LinkListTest; import java.util.HashMap; import java.util.Map; public class SingleLinkList implements ICommOperate<SNode>{ private SNode head = new SNode("HEAD") ; // 公共头指针,声明之后不变 private int size = 0 ; public int getSize() { return this.size; } /* * 链表插入,每次往末端插入 * */ @Override public boolean insertNode(SNode node) { boolean flag = false ; SNode current = this.head ; if( this.size==0 ){ // 空链表 this.head.setNextNode(node) ; node.setNextNode(null) ; }else{ // 链表内节点 while( current.getNextNode()!=null ){ current = current.getNextNode() ; } current.setNextNode(node) ; node.setNextNode(null) ; } this.size++ ; flag = true ; return flag; } /* * 插入链表指定位置pos,从1开始,而pos大于size则插入链表末端 * */ @Override public boolean insertPosNode(int pos, SNode node){ boolean flag = true; SNode current = this.head.getNextNode() ; if( this.size==0 ){ // 空链表 this.head.setNextNode(node) ; node.setNextNode(null) ; this.size++ ; }else if( this.size<pos ){ // pos位置大于链表长度,插入末端 insertNode(node) ; }else if( pos>0 && pos<=this.size) { // 链表内节点 // 1、找到要插入pos位置节点和前节点 int find = 0; SNode preNode = this.head; // 前节点 SNode currentNode = current; // 当前节点 while( find<pos-1 && currentNode.getNextNode()!=null ){ preNode = current ; // 前节点后移 currentNode = currentNode.getNextNode() ; // 当前节点后移 find++ ; } // System.out.println(preNode); // System.out.println(currentNode); // 2、插入节点 preNode.setNextNode(node); node.setNextNode(currentNode); this.size++ ; System.out.println("节点已经插入链表中"); }else{ System.out.println("位置信息错误"); flag = false ; } return flag; } /* * 指定链表的节点pos,删除对应节点。方式:找到要删除节点的前后节点,进行删除。从1开始 * */ @Override public boolean deleteNode(int pos) { boolean flag = false; SNode current = this.head.getNextNode() ; if( pos<=0 || pos>this.size || current==null ){ System.out.println("位置信息错误或链表无信息"); }else{ // 1、找到要删除节点的前后节点 int find = 0; SNode preNode = this.head; // 前节点 SNode nextNode = current.getNextNode(); // 后节点 while( find<pos-1 && nextNode.getNextNode()!=null ){ preNode = current ; // 前节点后移 nextNode = nextNode.getNextNode() ; // 后节点后移 find++ ; } // System.out.println(preNode); // System.out.println(nextNode); // 2、删除节点 preNode.setNextNode(nextNode); System.gc(); this.size-- ; flag = true ; } return flag; } /* * 指定链表的节点pos,修改对应节点。 从1开始 * */ @Override public boolean updateNode(int pos, Map<String, Object> map) { boolean flag = false ; SNode node = getNode(pos, map); // 获得相应位置pos的节点 if( node!=null ){ String data = (String) map.get("data") ; node.setData(data); flag = true ; } return flag; } /* * 找到指定链表的节点pos,从1开始 * */ @Override public SNode getNode(int pos, Map<String, Object> map) { SNode current = this.head.getNextNode() ; if( pos<=0 || pos>this.size || current==null ){ System.out.println("位置信息错误或链表不存在"); return null; } int find = 0 ; while( find<pos-1 && current!=null ){ current = current.getNextNode() ; find++ ; } return current; } /* * 打印链表 * */ @Override public void printLink() { int length = this.size ; if( length==0 ){ System.out.println("链表为空!"); return ; } SNode current = this.head.getNextNode() ; int find = 0 ; System.out.println("总共有节点数: " + length +" 个"); while( current!=null ){ System.out.println("第 " + (++find) + " 个节点 :" + current); current=current.getNextNode() ; } } public static void main(String[] args) { SingleLinkList sll = new SingleLinkList() ; SNode node1 = new SNode("节点1"); SNode node2 = new SNode("节点2"); SNode node3 = new SNode("节点3"); SNode node4 = new SNode("节点4"); SNode node5 = new SNode("节点5"); SNode node6 = new SNode("插入指定位置"); sll.insertPosNode(sll.getSize()+1, node1) ; sll.insertPosNode(sll.getSize()+1, node2) ; sll.insertPosNode(sll.getSize()+1, node3) ; sll.insertPosNode(sll.getSize()+1, node4) ; sll.insertPosNode(sll.getSize()+1, node5) ; // sll.insertNode(node1); // sll.insertNode(node2); // sll.insertNode(node3); // sll.insertNode(node4); // sll.insertNode(node5); System.out.println("*******************输出链表*******************"); sll.printLink(); System.out.println("*******************获得指定链表节点*******************"); int pos = 2 ; System.out.println("获取链表第 "+pos+" 个位置数据 :"+sll.getNode(pos, null)); System.out.println("*******************向链表指定位置插入节点*******************"); int pos1 = 2 ; System.out.println("将数据插入第 "+pos1+" 个节点:"); sll.insertPosNode(pos1, node6) ; sll.printLink(); System.out.println("*******************删除链表指定位置节点*******************"); int pos2 = 2 ; System.out.println("删除第 "+pos2+" 个节点:"); sll.deleteNode(pos2) ; sll.printLink(); System.out.println("*******************修改链表指定位置节点*******************"); int pos3 = 2 ; System.out.println("修改第 "+pos3+" 个节点:"); Map<String, Object> map = new HashMap<>() ; map.put("data", "this is a test") ; sll.updateNode(pos3, map) ; sll.printLink(); } }
; Classe d'opération d'interface :
Nœud de liste chaînée double :
package LinkListTest; import java.util.Map; public interface ICommOperate<T> { public boolean insertNode(T node) ; public boolean insertPosNode(int pos, T node) ; public boolean deleteNode(int pos) ; public boolean updateNode(int pos, Map<String, Object> map) ; public T getNode(int pos, Map<String, Object> map) ; public void printLink() ; }
package LinkListTest; // 双连表节点 public class DNode { private DNode priorNode; private String data; private DNode nextNode; public DNode(){ } public DNode(String data) { this.priorNode = new DNode() ; this.data = data ; this.nextNode = new DNode() ; } public DNode getPriorNode() { return priorNode; } public void setPriorNode(DNode priorNode) { this.priorNode = priorNode; } public String getData() { return data; } public void setData(String data) { this.data = data; } public DNode getNextNode() { return nextNode; } public void setNextNode(DNode nextNode) { this.nextNode = nextNode; } @Override public String toString() { return "DNode [data=" + data + "]"; } }
package LinkListTest; import java.util.HashMap; import java.util.Map; public class DoubleLinkList implements ICommOperate<DNode>{ private DNode head = new DNode("HEAD"); private int size = 0 ; public int getSize() { return this.size; } /* * 链表插入,每次往末端插入 * */ @Override public boolean insertNode(DNode node) { boolean flag = false; DNode current = this.head ; if( this.size==0 ){ // 空链表 this.head.setNextNode(node) ; node.setPriorNode(this.head); node.setNextNode(null) ; }else{ // 链表内节点 while( current.getNextNode()!=null ){ current = current.getNextNode() ; } current.setNextNode(node); node.setNextNode(null); node.setPriorNode(current); } this.size++ ; flag = true ; return flag; } /* * 插入链表指定位置pos,从1开始,而pos大于size则插入链表末端 * */ @Override public boolean insertPosNode(int pos, DNode node) { boolean flag = true; DNode current = this.head.getNextNode() ; if( this.size==0){ // 链表为空 this.head.setNextNode(node) ; node.setNextNode(null) ; node.setPriorNode(this.head); this.size++ ; }else if( pos>this.size ){ // pos位置大于链表长度,插入末端 insertNode(node) ; }else if( pos>0 && pos<=this.size ){ // 链表内节点 // 1、找到要插入位置pos节点,插入pos节点当前位置 int find = 0; while( find<pos-1 && current.getNextNode()!=null ){ current = current.getNextNode() ; find++ ; } // 2、插入节点 if( current.getNextNode()==null ){ // 尾节点 node.setPriorNode(current); node.setNextNode(null); current.setNextNode(node); } else if( current.getNextNode()!=null ) { //中间节点 node.setPriorNode(current.getPriorNode()); node.setNextNode(current); current.getPriorNode().setNextNode(node); current.setPriorNode(node); } this.size++ ; }else{ System.out.println("位置信息错误"); flag = false ; } return flag; } /* * 指定链表的节点pos,删除对应节点,从1开始 * */ @Override public boolean deleteNode(int pos) { boolean flag = false; DNode current = this.head.getNextNode() ; if( pos<=0 || pos>this.size || current==null ){ System.out.println("位置信息错误或链表不存在"); }else{ // 1、找到要删除位置pos节点 int find = 0; while( find<pos-1 && current.getNextNode()!=null ){ current = current.getNextNode() ; find++ ; } // 2、删除节点 if( current.getNextNode()==null ){ // 尾节点 current.getPriorNode().setNextNode(null) ; } else if( current.getNextNode()!=null ) { //中间节点 current.getPriorNode().setNextNode(current.getNextNode()) ; current.getNextNode().setPriorNode(current.getPriorNode()) ; } System.gc(); this.size-- ; flag = true ; } return flag; } /* * 指定链表的节点pos,修改对应节点。 从1开始 * */ @Override public boolean updateNode(int pos, Map<String, Object> map) { boolean flag = false ; DNode node = getNode(pos, map); if( node!=null ){ String data = (String) map.get("data") ; node.setData(data); flag = true ; } return flag; } /* * 找到指定链表的节点pos,从1开始 * */ @Override public DNode getNode(int pos, Map<String, Object> map) { DNode current = this.head.getNextNode() ; if( pos<=0 || pos>this.size || current==null ){ System.out.println("位置信息错误或链表不存在"); return null; } int find = 0 ; while( find<pos-1 && current!=null ){ current = current.getNextNode() ; find++ ; } return current; } /* * 打印链表 * */ @Override public void printLink() { int length = this.size ; if( length==0 ){ System.out.println("链表为空!"); return ; } DNode current = this.head.getNextNode() ; int find = 0 ; System.out.println("总共有节点数: " + length +" 个"); while( current!=null ){ System.out.println("第 " + (++find) + " 个节点 :" + current); current=current.getNextNode() ; } } public static void main(String[] args) { DoubleLinkList dll = new DoubleLinkList() ; DNode node1 = new DNode("节点1"); DNode node2 = new DNode("节点2"); DNode node3 = new DNode("节点3"); DNode node4 = new DNode("节点4"); DNode node5 = new DNode("节点5"); DNode node6 = new DNode("插入指定位置"); dll.insertPosNode(10, node1) ; dll.insertPosNode(10, node2) ; dll.insertPosNode(10, node3) ; dll.insertPosNode(10, node4) ; dll.insertPosNode(10, node5) ; // dll.insertNode(node1); // dll.insertNode(node2); // dll.insertNode(node3); // dll.insertNode(node4); // dll.insertNode(node5); System.out.println("*******************输出链表*******************"); dll.printLink(); System.out.println("*******************获得指定链表节点*******************"); int pos = 2 ; System.out.println("获取链表第 "+pos+" 个位置数据 :"+dll.getNode(pos, null)); System.out.println("*******************向链表指定位置插入节点*******************"); int pos1 = 2 ; System.out.println("将数据插入第"+pos1+"个节点:"); dll.insertPosNode(pos1, node6) ; dll.printLink(); System.out.println("*******************删除链表指定位置节点*******************"); int pos2 = 7 ; System.out.println("删除第"+pos2+"个节点:"); dll.deleteNode(pos2) ; dll.printLink(); System.out.println("*******************修改链表指定位置节点*******************"); int pos3 = 2 ; System.out.println("修改第"+pos3+"个节点:"); Map<String, Object> map = new HashMap<>() ; map.put("data", "this is a test") ; dll.updateNode(pos3, map) ; dll.printLink(); } }