下一篇双向链表
1、什么是链表
链表是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必按照顺序存储数据,链表
在插入的时候,比顺序存储结构的数组
快得多。相比数组(顺序存储结构)
,链表(链式存储结构)
可以充分利用计算机内存空间,实现灵活的内存动态管理。
下图是一个单链表示意图,通过下图能更好的理解上面的一些概念。
2、单向链表增删改查思路
单向链表是最简单的一种链表,它包含两个域,一个信息域和一个指向下一个节点的指针域
,指针域
指向列表中的下一个节点,而最后一个节点则指向一个空值。单向链表只可向一个方向遍历。
下图是一个带有头节点的单向链表逻辑示意图
提示:头结点是为了操作的统一与方便而设立的,放在第一个元素结点之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等)。是否带有头节点可根据实际需求而定。
2.1、在链表的最后添加节点
这种情况的添加,只需要找到链表中的最后一个节点,再将此节点的next域指向新节点即可。
2.2、将节点插入到指定的位置
- 首先找到新节点需要添加的位置
temp
- 将新节点的next域指向当前节点的下一个节点
newNode.next=temp.next
。 - 将当前节点的next域指向新节点
temp.next=newNode
结合下面的示意图,很好理解这种操作
2.3、节点删除
- 找到要删除节点的前一个节点,用
temp
变量表示 - 将要删除节点的前一个节点(
temp
)的next域,指向要删除节点的下一个节点。temp=temp.next.next
结合下面的示意图,能更直观的理解
2.4、节点更新
节点的更新比较简单,直接找到对应的节点,更新对应的数据即可。
3、代码实现
通过上面的分析,使用代码实现就比较简单了。这里使用java实现一个编程语言排名的单向链表。
1、定义ProgramLanguageNode类
class ProgramLanguageNode{
/**
* 排名
*/
private int no;
/**
* 名称
*/
private String name;
//下一个节点
private ProgramLanguageNode next;
public ProgramLanguageNode(int no, String name) {
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ProgramLanguageNode getNext() {
return next;
}
public void setNext(ProgramLanguageNode next) {
this.next = next;
}
@Override
public String toString() {
return "编程语言{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
2、实现单向链表
class SingleLinkedList{
//头节点,不存储数据。用于链表逻辑处理
private ProgramLanguageNode head;
public SingleLinkedList() {
this.head=new ProgramLanguageNode(-1,null);
}
public void add(ProgramLanguageNode node){
ProgramLanguageNode temp=head;
while (temp.getNext()!=null){
temp=temp.getNext();
}
temp.setNext(node);
}
/**
* 按照编程语言排名,添加到指定位置
*/
public void addByOrder(ProgramLanguageNode node){
ProgramLanguageNode temp=head;
while (true){
//已经为最后一个节点
if (temp.getNext()==null){
break;
}else if (temp.getNext().getNo()>=node.getNo()){//新节点应该在此节点的前面
break;
}
//当前节点后移
temp=temp.getNext();
}
//将当前节点的next域指向新节点
temp.setNext(node);
//将新节点的next域指向当前节点的下一个节点
node.setNext(temp.getNext());
}
/**
* 要删除节点的编号
* @param no
*/
public void del(int no){
ProgramLanguageNode temp=head;
//标识是否找到要删除的节点
boolean flag=false;
while (true){
if (temp.getNext()==null){
break;
}
if (temp.getNext().getNo()==no){
flag=true;
break;
}
//当前节点后移
temp=temp.getNext();
}
if (flag){
temp.setNext(temp.getNext().getNext());
}else {
System.out.printf("要删除的%d节点不存在",no);
}
}
/**
* 更新
* @param newNode
*/
public void update(ProgramLanguageNode newNode){
if (head.getNext()==null){
System.out.println("链表为空,没有数据!");
}
ProgramLanguageNode cur=head.getNext();
//是否找到要更新的数据
boolean flag=false;
while (cur!=null){
if (cur.getNo()==newNode.getNo()){
flag=true;
break;
}
cur=cur.getNext();
}
if (flag){
cur.setName(newNode.getName());
}else {
System.out.println("没有找到节点!");
}
}
/**
* 节点遍历
*/
public void list(){
if (head.getNext()==null){
System.out.println("链表为空,没有数据!");
}
ProgramLanguageNode tmp=head;
while (true){
if (tmp.getNext()==null){
break;
}
System.out.println(tmp.getNext().toString());
tmp=tmp.getNext();
}
}
}
3、链表测试
/**
* 测试
* @param args
*/
public static void main(String[] args) {
SingleLinkedList singleLinkedList=new SingleLinkedList();
singleLinkedList.addByOrder(new ProgramLanguageNode(1,"C"));
singleLinkedList.addByOrder(new ProgramLanguageNode(2,"JAVA"));
singleLinkedList.addByOrder(new ProgramLanguageNode(4,"C#"));
singleLinkedList.addByOrder(new ProgramLanguageNode(3,"JavaScript"));
singleLinkedList.addByOrder(new ProgramLanguageNode(5,"Python"));
System.out.println("原链表数据~~~~");
singleLinkedList.list();
System.out.println("删除后链表数据~~~~");
singleLinkedList.del(2);
singleLinkedList.list();
}