在算法思想上,对于单链表的快速排序和对于数组的快速排序基本一致,但是同时也存在很大的区别,导致的原因我们也很容易明白,那就是单链表不支持像数组那样的方便的访问下标,也就是说我们无法对其进行从末尾向前遍历。所以我们将第一个链表第一个结点的值作为左轴,然后向右进行遍历,设置一个small指针指向左轴的下一个元素,然后比较如果比左轴小的话,使small指针指向的数据与遍历到的数据进行交换。最后将左轴元素与small指针指向的元素交换即可。之后就是递归。具体图解如下:
下面附上代码:
void quicksort(Linklist head, Linklist end){ if(head == NULL || head == end) //如果头指针为空或者链表为空,直接返回 return ; int t; Linklist p = head -> next; //用来遍历的指针 Linklist small = head; while( p != end){ if( p -> data < head -> data){ //对于小于轴的元素放在左边 small = small -> next; t = small -> data; small -> data = p -> data; p -> data = t; } p = p -> next; } t = head -> data; //遍历完后,对左轴元素与small指向的元素交换 head -> data = small -> data; small -> data = t; quicksort(head, small); //对左右进行递归 quicksort(small -> next, end); }
此外,对于链表,快排还有其他的思路。那就是将基准定下来后,遍历链表,选择比基准小的连成一个新的子表,选择比基准大的连成一个新的子表,然后将基准插入,进而再对两个子表进行递归快排
void Quicksort(Linklist *head, Linklist end){ Linklist right; Linklist *p1; Linklist *p2; Linklist flag; Linklist old; int num, left_num, right_num; if(*head == end) return ; do{ flag = *head; //基准元素 p1 = head; //比基准元素小的链表 p2 = &right; //比基准元素大的链表 left_num = right_num = 0; //记录两个链表长度的大小 for(old =(*head) -> next; old != end; old = old -> next){ //遍历当前函数中的链表 if(old -> data < flag -> data){ //对于小于基准的元素,放在左链表中 left_num ++; *p1 = old; p1 = &(old -> next); } else{ ++right_num; //对于大于基准的元素,放在右链表中 *p2 = old; p2 = &(old -> next); } } *p2 = end; //封死右链表 *p1 = flag; //将基准插入在两个链表之间 flag -> next = right; if(left_num > right_num){ //对长度更小的链表进行递归快排运算 Quicksort(&(flag -> next), end); end = flag; num = left_num; } else{ Quicksort(head, flag); head = &(flag -> next); num = right_num; } }while(num > 1); }
对于链表中的快速排序暂时说这么多,但是实际上快排是不适合单链表的,应用归并排序效率更好