概览
上面一篇文章讲解了数组快速排序的实现,由于单向链表与数组天生差异,无法实现从后往前的指针遍历,所以考虑换一种方式来实现。
实现原理
既然不能从后往前进行指针遍历,那么就从前往后吧。同样的设定基准值pivot为链表的头结点的值,两个指针S(Small)和L(Large)分别指向头结点和头结点的next结点。我们的目标是保证S指针之前的元素都小于等于pivot,而S指针与L指针之间的数据都大与pivot,直到L指针指向最后一个结点。
判断L指向的结点的值是否大于pivot,如果否,则将S指针往后移动一个位置(我们一开始的目标就是S指针之前的结点值小于等于pivot,那么往后移动一个位置后的结点值必然大于pivot),交换S指针与L指针指向的结点的值,然后L指针往后移动;如果是,则只往后移动L指针,保持S指针不动。
不断进行以上操作,直到L指针指向链表最后一个结点。这时S指针之前(包括S指针指向的结点)的结点的值都小于等于pivot(不包括头结点,即设置pivot的结点),S指针和L指针之间的结点的值都大于pivot,然后交换S指针指向结点与头结点的值,完成一次排序。
再分别对(头结点-->Small指针指向的结点)以及(Small.next指针指向的结点-->尾结点)进行快速排序,最终得到完整链表的排序结果。
实现示例
实现代码
public class QuickSortLinkedList {
private static int MAXNUM = 10;
private static Node head = new QuickSortLinkedList.Node();
//定义结点数据结构
static class Node{
public int value;
public Node next;
}
/**
* 实现链表的快速排序算法
* @param head 链表的头结点
* @param end 链表的尾结点
*/
public static void quickSortLinkedList(Node head, Node end){
if(head != end){ //链表至少需要两个结点,即头结点和尾结点不能相同
int pivot = head.value; //得到基准值
Node small = head; //small指针
Node large = small.next; //large指针
while(large != end){ //如果large指针没有到尾结点
if(large.value < pivot){ //如果large指向的结点值小于基准值,需要交换
small = small.next; //small指针后移
if(small != large){ //如果不是指向同一个结点,则执行交换,否则不做处理
int temp = small.value;
small.value = large.value;
large.value = temp;
}
}
large = large.next; //large指针后移
}
int temp = small.value; //交换头结点和small指向的结点
small.value = head.value;
head.value = temp;
quickSortLinkedList(head, small); //对前半部分进行快速排序
quickSortLinkedList(small.next, end); //对后半部分进行快速排序
}
}
public static void main(String[] args) {
init(MAXNUM); //初始化链表
print();
System.out.println();
quickSortLinkedList(head, getEnd(head));
print();
}
/**
* 链表初始化,每个结点的值随机生成为1-100之间
* @param n 链表的长度
*/
public static void init(int n){
Node current = head;
for(int i = 0; i < n; i++){
current.value = (int) (Math.random()*100 +1); //结点的值随机为1-100之间
current.next = new QuickSortLinkedList.Node();
current = current.next;
}
}
/**
* 链表的打印
*/
public static void print(){
Node current = head;
while(current.next != null){
System.out.print(current.value + " ");
current = current.next;
}
}
/**
* 得到链表的最后一个结点
* @param head 链表的头结点
* @return end 链表的尾结点
*/
public static Node getEnd(Node head){
Node current = head;
while(current.next != null){
current = current.next;
}
Node end = current;
return end;
}
}