字节面试考到了单链表排序,要求使用快排,自定义单链表数据结构,面试结束之后复盘,使用java写了四种排序算法,分别是插入,归并和快速排序;
/**
* @author yangshiwei
* 单链表的四种排序算法
*/
public class ListSortUtils {
static class ListNode {
int val;
ListNode next;
public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ListNode: ").append(val);
while (next.next != null) {
sb.append(" -> ").append(next.val);
next = next.next;
}
return sb.toString();
}
}
public void bubbleSort(ListNode head){
boolean flag = true;
ListNode dummy = head;
while(flag && dummy != null){
flag = false;
ListNode pre = dummy;
while(pre.next != null){
if(pre.val > pre.next.val){
int tmp = pre.val;
pre.val = pre.next.val;
pre.next.val = tmp;
flag = true;
}
pre = pre.next;
}
dummy = dummy.next;
}
}
/**
* 插入排序
* 时间复杂度 O(n ^ 2)
* 空间复杂度 O(1)
* @param head ListNode
* @return ListNode
*/
public void insertionSortList(ListNode head) {
if (head == null || head.next == null) return;
ListNode pre = head;
ListNode cur = head.next;
ListNode aux = new ListNode(-1, head); // 辅助结点
while (cur != null) {
if (cur.val < pre.val) {
// 先把cur 节点从当前链表中删除、然后再把cur结点插入到l1和l2之间
pre.next = cur.next;
// 从前往后找到 l2.val > cur .val,然后把cur节点插入到l1 和l2之间
ListNode l1 = aux;
ListNode l2 = aux.next;
while (cur.val > l2.val) {
l1 = l2;
l2 = l2.next;
}
l1.next = cur;
cur.next = l2;
cur = pre.next; //指向下一个待处理节点
} else {
pre = cur;
cur = cur.next;
}
}
}
/**
* 归并排序 自顶向下
* 时间复杂度 O(NlogN)
* 空间复杂度 O(logN) 递归调用的栈空间
* @param head ListNode
* @return LisNode
*/
public ListNode mergeSort(ListNode head){
return mergeSort(head,null);
}
public ListNode mergeSort(ListNode head, ListNode tail) {
if (head == null) {
return head;
}
if (head.next == tail) {
head.next = null;
return head;
}
// get mid
ListNode slow = head, fast = head;
while (fast != tail) {
slow = slow.next;
fast = fast.next;
if (fast != tail) {
fast = fast.next;
}
}
ListNode mid = slow;
ListNode list1 = mergeSort(head, mid);
ListNode list2 = mergeSort(mid, tail);
ListNode sorted = merge(list1, list2);
return sorted;
}
public ListNode merge(ListNode head1, ListNode head2) {
ListNode dummyHead = new ListNode(0);
ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
while (temp1 != null && temp2 != null) {
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
if (temp1 != null) {
temp.next = temp1;
} else if (temp2 != null) {
temp.next = temp2;
}
return dummyHead.next;
}
/**
* 快速排序
* 时间复杂度 O(NlogN) 可能会退化
* 空间复杂度 O(1)
* @param head ListNode
* @param end ListNode
*/
public void quickSort(ListNode head, ListNode end) {
if (head != end) {
ListNode node = portion(head, end);
quickSort(head, node);
quickSort(node.next, end);
}
}
private ListNode portion(ListNode head, ListNode end) {
ListNode p1 = head ,p2 =head.next;
while(p2 != end){
if(p2.val < head.val){
p1 = p1.next;
int tmp = p2.val;
p2.val = p1.val;
p1.val = tmp;
}
p2 = p2.next;
}
if(p1 != head){
int tmp = p1.val;
p1.val = head.val;
head.val = tmp;
}
return p1;
}
public void quickSort(ListNode head){
quickSort(head,null);
}
}