将大的数据放在x的右边,小的数据放在x的左边
思路:
- 将原链表分割为两个链表:一个链表是存大于元素X的节点,另一个链表存小于元素X的节点。
- 遍历完整个链表之后,将新产生的两个链表串起来。
下面提供两种方法,其实大同小异,但是因为链表的最后一个元素需要指向空,如果少了这个就会出现问题。所以在方法二中,遍历的过程就将末尾指向空。
方法一:
//将大的数据放在x的右边,小的数据放在x的左边
public ListNode parttition(int x) {
ListNode cur = this.head;
ListNode beforeStart = null;
ListNode beforeEnd = null;
ListNode afterStart = null;
ListNode afterEnd = null;
while (cur != null) {
if (cur.data < x) {
//判断是否是第一次插入
if (beforeStart == null) {
beforeStart = cur;
beforeEnd = beforeStart;
} else {
beforeEnd.next = cur;
beforeEnd = cur;
}
} else {
//第一次插入
if (afterStart == null) {
afterStart = cur;
afterEnd = afterStart;
} else {
afterEnd.next = cur;
afterEnd = cur;
}
}
cur = cur.next;
}
//小部分的头要是为空,则返回大部分的头
if (beforeStart == null) {
return afterStart;
}
//将两部分串起来
beforeEnd.next = afterStart;
if (afterStart != null)//大部分不等于空的时候,将大部分最后节点的next指向空
{
afterEnd.next = null;
}
return beforeStart;
}
方法二:
//将大的数据放在x的右边,小的数据放在x的左边
//改进版
public ListNode parttition2(int x) {
ListNode cur = this.head;
ListNode beforeStart = null;
ListNode beforeEnd = null;
ListNode afterStart = null;
ListNode afterEnd = null;
while (cur != null) {
//每个节点都可能成为最后一个节点(尾节点)
ListNode curNext = cur.next;
cur.next = null;
if (cur.data < x) {
//判断是否是第一次插入
if (beforeStart == null) {
beforeStart = cur;
beforeEnd = beforeStart;
} else {
beforeEnd.next = cur;
beforeEnd = cur;
}
} else {
//第一次插入
if (afterStart == null) {
afterStart = cur;
afterEnd = afterStart;
} else {
afterEnd.next = cur;
afterEnd = cur;
}
}
//cur = cur.next;
cur = curNext;
}
//小部分的头要是为空,则返回大部分的头
if (beforeStart == null) {
return afterStart;
}
//将两部分串起来
beforeEnd.next = afterStart;
return beforeStart;
}
删除重复的节点
//删除重复的节点
public ListNode deleteDuplication() {
//虚拟节点
ListNode node = new ListNode(-1);
ListNode cur = this.head;
ListNode tmp = node;
while (cur != null) {
if (cur.next != null && cur.next.data == cur.data) {
//循环
while ( cur.next != null && cur.data == cur.next.data) {
cur = cur.next;
}
//退出循环需要多走一步
cur = cur.next;
//the first way
tmp.next=cur;
} else {
tmp.next = cur;
tmp = tmp.next;
cur = cur.next;
}
}
//the second way
// tmp.next = null;
return node.next;
}
判断链表是否为回文
思路:使用快慢指针,将后边链表进行反转,然后两段进行循环对比判断是否为回文。
//判断回文
public boolean chkPalindrome()
{
ListNode slow=this.head;
ListNode fast=this.head;
//定义快慢指针
while(fast!=null && fast.next!=null)
{
slow=slow.next;
fast=fast.next.next;
}
ListNode p=slow.next;
//将后半链表指向反转
while(p!=null)
{
ListNode pNext=p.next;
p.next=slow;
slow=p;
p=pNext;
}
//judge Palindrome
ListNode phead=this.head;
while(phead!=slow)
{
if(phead.data!= slow.data)
{
return false;
}
//偶数
if(phead.next==slow)
{
return true;
}
phead=phead.next;
slow=slow.next;
}
return true;
}
判断这个链表中是否有环:
思路:见博客: https://blog.csdn.net/yuiop123455/article/details/108756602.
//在链表中创建一个环
public void createLoop()
{
ListNode cur=this.head;
while(cur.next!=null)
{
cur=cur.next;
}
System.out.println("3");
cur.next=this.head.next;
}
//判断这个链表中是否有环
public boolean hasCycle1() {
ListNode slow = this.head;
ListNode fast = this.head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;
}
}
return false;
}
寻找链表中环的入口
思路见博客:链接: https://blog.csdn.net/yuiop123455/article/details/108972864.
public ListNode detectCycle()
{
ListNode slow=this.head;
ListNode fast=this.head;
//先找到第一次相遇的地方
while(fast!=null && fast.next!=null)
{
slow=slow.next;
fast=fast.next.next;
if(slow==fast)
{
break;
}
}
//没有环则返回null
if(fast==null || slow==null)
{
return null;
}
// 让其中一个引用处于头的位置,另一个引用不动,两个引用分别一人一步走
slow=this.head;
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}
求链表中环的长度
思路见博客: 环形链表 III (求链表中环的长度).
//求链表中环的长度
public int cycleListLength()
{
ListNode slow=this.head;
ListNode fast=this.head;
//先找到第一次相遇的地方
while(fast!=null && fast.next!=null)
{
slow=slow.next;
fast=fast.next.next;
if(slow==fast)
{
break;
}
}
//没有环则返回null
if(fast==null || fast.next==null)
{
return -1;
}
// 让其中一个引用处于头的位置,另一个引用不动,其中一个引用一步一步向后走,用count计数,直到两个引用相遇
slow=this.head;
int count=1;
slow=slow.next;//让slow先走一步
while(slow!=fast){
count++;
slow=slow.next;
}
return count;
}