链表
定义:线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素
特点:
- 链表是以节点的方式来存储,是链式存储。
- 每个节点包含 data域, next 域:指向下一个节点;循环链表还有pre域:指向前一个节点。
- 链表的各个节点不一定是连续存储。
- 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定
- (划重点)单链表:访问后继节点的时间复杂度为O(1);访问前驱节点的时间复杂度为O(n)
简单的链表都是老生常谈的话题了,所以作为复习就只关注一些重点和较难的链表问题:
1.双向链表:
前驱指针+后驱指针:next+pre
头节点:head
代码示例:
//节点
public class Node {
//数据域
private String userName;
private String passWord;
//指针域
private Node pre;
private Node next;
public Node(String name, String password){
this.userName = name;
this.passWord = password;
}
public Node(){}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public Node getPre() {
return pre;
}
public void setPre(Node pre) {
this.pre = pre;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
//链表
public class MyLinkList {
private Node head;
public MyLinkList(){}
public MyLinkList(Node head){
this.head = head;
}
//常见方法
//判断是否为空
public boolean isEmpty(){
return head == null;
}
//找到最后一个节点
public Node findLastNode(){
if (this.head == null){
throw new RuntimeException("链表为空");
}else {
Node loc = this.head;
while(loc.getNext() != null){
loc = loc.getNext();
}
return loc;
}
}
//加入一个节点(尾插法)
public void addNode(Node newNode){
//如果是空链表
if (isEmpty()){
head.setNext(newNode);
newNode.setPre(head);
}else {
Node temp = findLastNode();
temp.setNext(newNode);
newNode.setPre(temp);
}
}
//删除最后一个节点
public void deleteLast(){
if (isEmpty()){
throw new RuntimeException("链表为空");
}else {
Node temp = findLastNode();
temp.getPre().setNext(null);
temp.setPre(null);
}
}
//从头到尾打印链表
public void showAll(){
if (this.head == null){
throw new RuntimeException("链表为空");
}else {
Node loc = this.head;
while(loc.getNext() != null){
System.out.println(loc.getUserName()+":"+loc.getPassWord());
loc = loc.getNext();
}
System.out.println(loc.getUserName()+":"+loc.getPassWord());
}
}
//从某处增加、删除某个节点
public void addMiddle(Node newNode, String str) {
if (isEmpty()) {
head.setNext(newNode);
newNode.setPre(head);
} else {
Node loc = this.head;
while (true) {
if (loc.getUserName() == str) {
//找到了那个节点 开始插入
if (loc.getNext() != null){//如果不是尾节点,就给加入后继节点
newNode.setNext(loc.getNext());
loc.getNext().setPre(newNode);
}
newNode.setPre(loc);
loc.setNext(newNode);
break;
}else {
if (loc.getNext() == null) break;
else loc = loc.getNext();
}
}
}
}
}
public class Application {
public static void main(String[] args) {
Node newNode = new Node("zhangsan","123456");
MyLinkList myLinkList = new MyLinkList(newNode);
Node newNode2 = new Node("lisi","123456");
myLinkList.addNode(newNode2);
Node newNode3 = new Node("jack","123456");
Node newNode4 = new Node("tomcat","123456");
myLinkList.addNode(newNode3);
myLinkList.addNode(newNode4);
Node newNode5 = new Node("spring","123456");
myLinkList.addMiddle(newNode5,"jack");
myLinkList.showAll();
}
}
tips:如果要双向循环链表的话,直接将最后一个节点的后继指针指向第一个节点就好了。last.next = head;
2.经典面试题:单链表的反转
部分代码:
public void reverseList(){
//如果链表为空,直接返回
if(head == null){
return;
}
//如果只有一个节点,直接返回这个节点就好
if(head.next == null){
return head;
}
//
//定义一个临时指针
Node temp = this.head;
Node next = null;//指向temp的下一个节点
Node newHead = null;//定义新链表的头节点
while(temp != null){
next = temp.next;//
temp.next = newHead;
newHead = temp;
temp = next;
}
head = newHead;
}