①普通的打印
a.定义this.head=cur;
b.当cur!=null时,挨着打印
c.cur=cur.next;
public void display() {
//用cur是为了确保head的存在,不然用head的话,遍历完成后将找不到头结点的位置
ListNode cur = head;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}//换行
System.out.println();
}
②从指定头节点开始打印
a将指定节点设置为newHead
b.然后就是普通的打印了
public void display2(ListNode newHead) {
//用cur是为了确保head的存在,不然用head的话,遍历完成后将找不到头结点的位置
//将指定位置设置为newHead
ListNode cur = newHead;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
③查找是否包含关键字key是否在单链表当中
(实质上就是遍历的思路)
public boolean contains(int key) {
ListNode cur=this.head;
while(cur!=null){
if(this.cur.val==key){
return true;
}cur=cur.next;
}
return false;
}
④单链表的长度
(定义一个计数器,每遍历一个count++)
public int size() {
int count=0;
ListNode cur=this.head;
while(cur!=null){
count++;
cur=cur.next;
}
return count;
}
⑤头插法
a.使该插入节点的指针域指向下一个位置
b.将头节点指向于刚刚插入的结点
代码:
public void addFirst(int data) {
//定义这个即将要插入的结点节点
ListNode node=new ListNode(data);
node.next=this.head;
this.head=node;
}
?⑥尾插法(注意判断单链表是否为空的情况)
a.遍历到尾节点
b.使尾节点的指针域指向即将插入的节点
?代码:
public void addLast(int data) {
ListNode node= new ListNode(data);
//当单链表为空时,直接插入该节点
if(this.head==null){
this.node=head;
}else{//寻找尾节点
ListNode cur=this.head;
while(cur.next!=null){
cur=cur.next;
}
cur.next=node;
}
}
⑦任意位置插入一个元素,且第一个数据节点为0下标
(插入到某个位置,就要找它前面的那一个位置)
a.不符合条件的情况,index<0或者index>size()
b.当index=0,则就为头插
c.当index=size(),就为尾插
d.其它位置的话,需要先找到其前面那一个位置
public ListNode findIndex(int index) {
ListNode cur = this.head;
while (index - 1 != 0) {
cur = cur.next;
index--;
}
return cur;
}
//任意位置插入一个元素,且第一个数据节点为0下标
public void addIndex(int index, int data) {
if (index < 0 || index > size()) {
System.out.println("index位置不合法");
return;
}
if (index == 0) {
addFirst(data);
}
if (index == size()) {
addLast(data);
return;
}
ListNode cur = findIndex(index);
ListNode node = new ListNode(data);
node.next = cur.next;
cur.next = node;
}
⑧删除第一次出现关键字为key的节点
a.遍历找到key值所在的节点
b.使该节点的前一位的指针域直接指向该节点后一位的指针域
public ListNode searchPery(int key) {
ListNode cur = this.head;
while (cur.next != null) {
if (cur.next.val == key) {
return cur;//是就是直接读取
}
cur = cur.next;//不等于就接着往后面找
}
return null;
}
//删除第一次出现关键字为key的节点
public void remove(int key) {
if (this.head == null) {
System.out.println("此链表为空链表!不能删除");
return;
}
if (this.head.val == key) {
this.head = this.head.next;
}
ListNode cur = searchPery(key);
if (cur == null) {
System.out.println("没有你要删除的节点!");
return;
}
ListNode del = cur.next;
cur.next = del.next;
}
⑨删除所有值为key的节点
a.遍历找到a的位置
b.对key值节点进行删除,需要注意的是,由于删除的节点不止一个,因此,我们需要记住被删除节点的前一个节点的位置,否则就会丢失单链表
代码:
public void removeAllKey(int key) {
if(this.head==null){
return ;
}
ListNode prev=this.head;
ListNode head=this.head.next;
//先不判断头节点
while(cur!=null){
if(cur.val==key){
prev.next=cur.next;
cur=cur.next;
}else{
cur=prev;
cur=cur.next;
}
}
//处理头节点
if(this.head.val==key){
this.head=this.head.next;
}
}
⑩清空链表
(即把每个位置的指针域置为null)
public void clear() {
while (this.head != null) {
ListNode curNext = head.next;
this.head.next = null;
this.head = curNext;
}
}
①反转链表
a.找一个prev节点,将其值置为空,其作用为将每个节点的指针域转换指向
b.找一个节点curNext记录cur即将要走的下一个位置
c.而cur的存在,当cur=null时,表明原链表以遍历到尾节点,将尾节点转换为头节点后,整个反转链表得以完成
代码:
public ListNode reverseList() {
if(this.head==null){
return null;
}
ListNode cur=this.head;
ListNode prev=null;
while(cur!=null){
ListNode curNext=cur.next;
cur.next=prev;
prev=cur;
cur=curNext;
}
return prev;
}
②找到链表中倒数第k个节点
a.设置fast,slow两个指针同时移动fast,slow节点
b.根据倒数第k个节点所离尾节点的位置,让fast节点先走对应的步数,然后当fast==null时,slow所指的位置即为倒数第k个节点的位置
代码:
public ListNode FindKthToTail(int k) {
if(k<0||head==null){
System.out.println("此时找不到想要的节点");
}
ListNode fast=this.head;
ListNode slow=this.head;
while(k-1!=0){
fast=fast.next;
if(fast==null){
return null;}
k--;
}
while(fast!=null&&fast.next!=null){
fast=fast.next;
slow=slow.next;
}return slow;
}
③找到一个x,以x为大小将一个链表分成两个部分,均不改变原来链表的顺序,最后连接在一起
a.题意为:根据x将值分为大于x的和小于x的分别放于两个不同的链表中,最后将两个链表连接在一起
b.需要创建两个新的链表as,ae=null;bs,be=null;
c.需要注意是否是第一次插入,以及是否只有一个链表的情况(即均大于或者均小于)
public ListNode partition(int x) {
ListNode as=null;
ListNode ae=null;
ListNode bs=null;
ListNode be=null;
while(cur!=null){
if(cur.val<x){
//第一次插入值
if(as==null){
as=cur;
ae=cur;
}else{//非第一次插入值
ae.next=cur;
ae=ae.next;
}
}else if(cur.val>=x){
if(bs==null){
bs=cur;
be=cur;
}else{//非第一次插入
be.next=cur;
be=be.next;
}cur=cur.next;
}
if (as == null) {//预防第一个节点所在的段为空,即没有比x小的数
return bs;
}
ae.next = bs;
if (bs != null) {//保证最后一个节点为空
be.next = null;
}
return bs;
}
④判断链表是否是回文结构
a.要判断是否回文,首先要找到中间的节点,然后以中间节点为对称点,看是两端值是否一致这里可以设置两个指针一个fast,一个slow,fast一次两步,slow一次一步,当fast.next=null时,slow所指即为中间节点
b.找到中间值后,将后半部分进行链表的反转,反转后分别从两头进行比较值是否相等,若均相等则为回文结构,反之则不是回文结构
代码:?
public boolean chkPalindrome() {
if(head==null){
return true;
}
ListNode fast=this.head;
ListNode slow=this.head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}//得到了中间值slow,下面进行反转链表
ListNode cur = slow.next;//将中间节点的next域置为null
while (cur != null) {
ListNode curNext = cur.next;
cur.next = slow;
slow = cur;
cur = curNext;
}//反转完成,下面开始判断是否回文
while (head != slow) {//此时反转后的链表的头节点为slow
if (head.val != slow.val) {//只要有一对值不等,那么就返回false
return false;
}
if (head.next.val == slow.val) {//表明只有两个节点
return true;
}
head = head.next;
slow = slow.next;
}
return true;
}
⑤判断一个链表是否有环
(若是一个链表有环,那么易知,最后一个节点的指针域必然指向头节点)
a.同样设置fast和slow两个指针,一个一次两步,一个一次一步,若有环的话,两者必然会相遇,若两者不相遇,或者是快的指针指向了null,那么显然不存在环的结构
代码:?
public boolean hasCycle() {
if (head == null) return false;
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || fast.next == null) {
return false;
}
return true;
}
⑥构造一个环进行操作
(实质上就是让尾节点的指针域指向头节点)
a.构造一个环
public void createLoop() {
ListNode cur = this.head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = head.next.next;
}
b.对环进行相应的操作,找相遇点,很明了是在已经是环的基础上进行的操作
//一个从头开始,一个从相遇点开始,最后相遇的地方就是入口点
public ListNode detectCycle() {
if (head == null) return null;
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || fast.next == null) {
return null;
}
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
⑦合并两个有序的链表
a.要创建一个新的链表
b.将原来两个链表的值进行比较,谁小谁先插入新的链表
c.若是出现一者已经走完,则把另一个链表接连在后面即可
代码:
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode node = new ListNode();
ListNode tmp = node;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
tmp.next = l1;
l1 = l1.next;
tmp = tmp.next;
}
else {
tmp.next = l2;
l2 = l2.next;
tmp = tmp.next;
}
}
if (l1 != null) {
tmp.next = l1;
}
if (l2 != null) {
tmp.next = l2;
}
return node.next;
}
}