链表是一个线性数据结构,其中的元素是不能存储在连续的存储单元。
按升序对单向链表的节点进行排序:
我们可以通过多种排序技术对 LinkedList 进行排序:
- 冒泡排序
- 插入排序
- 快速排序
- 归并排序
方法 1:使用冒泡排序进行排序
- 为了完成这个任务,我们维护了两个指针:current 和 index。
- 最初,当前指向头节点,索引将指向当前旁边的节点。
- 通过比较当前的数据和索引的数据,遍历列表直到当前指向空。
- 对于每个当前的值,索引是当前节点的下一个,从当前的下一个节点遍历到空。
- 然后将当前节点的值与其下一个节点到最后一个节点的每个值进行比较,如果该值小于当前值,则交换这些值,这样最小值作为当前索引。
Java
// Java program to sort a Linked List using Bubble Sort
public class SortList {
// Represent a node of the singly linked list
class Node {
int data;
Node next;
public Node(int data)
{
this.data = data;
this.next = null;
}
}
// Represent the head and tail of the singly linked list
public Node head = null;
public Node tail = null;
// addNode() will add a new node to the list
public void addNode(int data)
{
// Create a new node
Node newNode = new Node(data);
// Checks if the list is empty
if (head == null) {
// If list is empty, both head and tail will
// point to new node
head = newNode;
tail = newNode;
}
else {
// newNode will be added after tail such that
// tail's next will point to newNode
tail.next = newNode;
// newNode will become new tail of the list
tail = newNode;
}
}
// sortList() will sort nodes of the list in ascending
// order
public void sortList()
{
// Node current will point to head
Node current = head, index = null;
int temp;
if (head == null) {
return;
}
else {
while (current != null) {
// Node index will point to node next to
// current
index = current.next;
while (index != null) {
// If current node's data is greater
// than index's node data, swap the data
// between them
if (current.data > index.data) {
temp = current.data;
current.data = index.data;
index.data = temp;
}
index = index.next;
}
current = current.next;
}
}
}
// display() will display all the nodes present in the
// list
public void display()
{
// Node current will point to head
Node current = head;
if (head == null) {
System.out.println("List is empty");
return;
}
while (current != null) {
// Prints each node by incrementing pointer
System.out.print(current.data + " ");
current = current.next;
}
System.out.println();
}
public static void main(String[] args)
{
SortList sList = new SortList();
// Adds data to the list
sList.addNode(8);
sList.addNode(3);
sList.addNode(7);
sList.addNode(4);
// Displaying original list
System.out.println("Original list: ");
sList.display();
// Sorting list
sList.sortList();
// Displaying sorted list
System.out.println("Sorted list: ");
sList.display();
}
}
Java
// Java program to sort Linked List using Insertion Sort
public class LinkedlistIS
{
node head;
node sorted;
class node
{
int val;
node next;
public node(int val)
{
this.val = val;
}
}
void push(int val)
{
// allocate node
node newnode = new node(val);
// link the old list off the new node
newnode.next = head;
// move the head to point to the new node
head = newnode;
}
// function to sort a singly linked list using insertion sort
void insertionSort(node headref)
{
// Initialize sorted linked list
sorted = null;
node current = headref;
// Traverse the given linked list and insert every
// node to sorted
while (current != null)
{
// Store next for next iteration
node next = current.next;
// insert current in sorted linked list
sortedInsert(current);
// Update current
current = next;
}
// Update head_ref to point to sorted linked list
head = sorted;
}
// function to insert a new_node in a list. Note that
// this function expects a pointer to head_ref as this
// can modify the head of the input linked list
// (similar to push())
void sortedInsert(node newnode)
{
// Special case for the head end
if (sorted == null || sorted.val >= newnode.val)
{
newnode.next = sorted;
sorted = newnode;
}
else
{
node current = sorted;
// Locate the node before the point of insertion
while (current.next != null && current.next.val < newnode.val)
{
current = current.next;
}
newnode.next = current.next;
current.next = newnode;
}
}
// Function to print linked list
void printlist(node head)
{
while (head != null)
{
System.out.print(head.val + " ");
head = head.next;
}
}
// Driver program to test above functions
public static void main(String[] args)
{
LinkedlistIS list = new LinkedlistIS();
list.push(4);
list.push(7);
list.push(3);
list.push(8);
System.out.println("Linked List before Sorting..");
list.printlist(list.head);
list.insertionSort(list.head);
System.out.println("\nLinkedList After sorting");
list.printlist(list.head);
}
}
Java
// Java program for Quick Sort on Singly Linked List
public class QuickSortLinkedList
{
static class Node
{
int data;
Node next;
Node(int d)
{
this.data = d;
this.next= null;
}
}
Node head;
void addNode(int data)
{
if(head == null)
{
head = new Node(data);
return;
}
Node curr = head;
while(curr.next != null)
curr = curr.next;
Node newNode = new Node(data);
curr.next = newNode;
}
void printList(Node n)
{
while(n != null)
{
System.out.print(n.data);
System.out.print(" ");
n = n.next;
}
}
// takes first and last node,
// but do not break any links in
// the whole linked list
Node paritionLast(Node start, Node end)
{
if(start == end ||
start == null || end == null)
return start;
Node pivot_prev = start;
Node curr = start;
int pivot = end.data;
// iterate till one before the end,
// no need to iterate till the end
// because end is pivot
while(start != end )
{
if(start.data < pivot)
{
// keep tracks of last modified item
pivot_prev = curr;
int temp = curr.data;
curr.data = start.data;
start.data = temp;
curr = curr.next;
}
start = start.next;
}
// swap the position of curr i.e.
// next suitable index and pivot
int temp = curr.data;
curr.data = pivot;
end.data = temp;
// return one previous to current
// because current is now pointing to pivot
return pivot_prev;
}
void sort(Node start, Node end)
{
if(start == end )
return;
// split list and partion recurse
Node pivot_prev = paritionLast(start, end);
sort(start, pivot_prev);
// if pivot is picked and moved to the start,
// that means start and pivot is same
// so pick from next of pivot
if( pivot_prev != null &&
pivot_prev == start )
sort(pivot_prev.next, end);
// if pivot is in between of the list,
// start from next of pivot,
// since we have pivot_prev, so we move two nodes
else if(pivot_prev != null &&
pivot_prev.next != null)
sort(pivot_prev.next.next, end);
}
// Driver Code
public static void main(String[] args)
{
QuickSortLinkedList list = new QuickSortLinkedList();
list.addNode(8);
list.addNode(3);
list.addNode(7);
list.addNode(4);
Node n = list.head;
while(n.next != null)
n= n.next;
System.out.println("Original List: ");
list.printList(list.head);
list.sort(list.head , n);
System.out.println("\nSorted List: ");
list.printList(list.head);
}
}
Java
// Java program to sort linkedList using Merge Sort
public class linkedList
{
node head = null;
// node a, b;
static class node {
int val;
node next;
public node(int val)
{
this.val = val;
}
}
node sortedMerge(node a, node b)
{
node result = null;
// Base cases
if (a == null)
return b;
if (b == null)
return a;
// Pick either a or b, and recur
if (a.val < b.val)
{
result = a;
result.next = sortedMerge(a.next, b);
}
else
{
result = b;
result.next = sortedMerge(a, b.next);
}
return result;
}
node mergeSort(node h)
{
// Base case : if head is null
if (h == null || h.next == null)
{
return h;
}
// get the middle of the list
node middle = getMiddle(h);
node nextofmiddle = middle.next;
// set the next of middle node to null
middle.next = null;
// Apply mergeSort on left list
node left = mergeSort(h);
// Apply mergeSort on right list
node right = mergeSort(nextofmiddle);
// Merge the left and right lists
node sortedlist = sortedMerge(left, right);
return sortedlist;
}
// Utility function to get the middle of the linked list
public static node getMiddle(node head)
{
if (head == null)
return head;
node slow = head, fast = head;
while (fast.next != null && fast.next.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
void push(int new_data)
{
// allocate node
node new_node = new node(new_data);
// link the old list off the new node
new_node.next = head;
// move the head to point to the new node
head = new_node;
}
// Utility function to print the linked list
void printList(node headref)
{
while (headref != null) {
System.out.print(headref.val + " ");
headref = headref.next;
}
}
public static void main(String[] args)
{
linkedList li = new linkedList();
li.push(4);
li.push(7);
li.push(3);
li.push(8);
System.out.print("\nOriginal List: \n");
li.printList(li.head);
// Apply merge Sort
li.head = li.mergeSort(li.head);
System.out.print("\nSorted List: \n");
li.printList(li.head);
}
}
Original list:
8 3 7 4
Sorted list:
3 4 7 8
时间复杂度: O(n ^ 2)
空间复杂度: O(1)
方法 2:使用插入排序进行排序
- 在插入排序技术中,我们假设列表中当前元素之前的所有元素都已经排序,我们从当前元素开始。
- 当前元素与它之前的所有元素进行比较,如果不按顺序交换。对所有后续元素重复此过程。
- 通常,插入排序技术将每个元素与其之前的所有元素进行比较,并对元素进行排序以将其放置在适当的位置。
如前所述,插入排序技术对于较小的数据集更可行,因此可以使用有效的插入排序对具有少量元素的数组进行排序。
插入排序在对链表数据结构进行排序时特别有用。如您所知,链表具有指向其下一个元素(单链表)和前一个元素(双链表)的指针。这样可以更轻松地跟踪上一个和下一个元素。
Java
// Java program to sort Linked List using Insertion Sort
public class LinkedlistIS
{
node head;
node sorted;
class node
{
int val;
node next;
public node(int val)
{
this.val = val;
}
}
void push(int val)
{
// allocate node
node newnode = new node(val);
// link the old list off the new node
newnode.next = head;
// move the head to point to the new node
head = newnode;
}
// function to sort a singly linked list using insertion sort
void insertionSort(node headref)
{
// Initialize sorted linked list
sorted = null;
node current = headref;
// Traverse the given linked list and insert every
// node to sorted
while (current != null)
{
// Store next for next iteration
node next = current.next;
// insert current in sorted linked list
sortedInsert(current);
// Update current
current = next;
}
// Update head_ref to point to sorted linked list
head = sorted;
}
// function to insert a new_node in a list. Note that
// this function expects a pointer to head_ref as this
// can modify the head of the input linked list
// (similar to push())
void sortedInsert(node newnode)
{
// Special case for the head end
if (sorted == null || sorted.val >= newnode.val)
{
newnode.next = sorted;
sorted = newnode;
}
else
{
node current = sorted;
// Locate the node before the point of insertion
while (current.next != null && current.next.val < newnode.val)
{
current = current.next;
}
newnode.next = current.next;
current.next = newnode;
}
}
// Function to print linked list
void printlist(node head)
{
while (head != null)
{
System.out.print(head.val + " ");
head = head.next;
}
}
// Driver program to test above functions
public static void main(String[] args)
{
LinkedlistIS list = new LinkedlistIS();
list.push(4);
list.push(7);
list.push(3);
list.push(8);
System.out.println("Linked List before Sorting..");
list.printlist(list.head);
list.insertionSort(list.head);
System.out.println("\nLinkedList After sorting");
list.printlist(list.head);
}
}
Linked List before Sorting..
8 3 7 4
LinkedList After sorting
3 4 7 8
时间复杂度: O(n ^ 2)
空间复杂度: O(1)
方法 3:使用快速排序进行排序
快速排序遵循分而治之的方法。它选取一个元素作为枢轴并围绕选取的枢轴对给定数组进行分区。
quickSort 中的关键过程是 partition()。分区的目标是,给定一个数组和数组的一个元素 x 作为主元,将 x 放在已排序数组中的正确位置,并将所有较小的元素(小于 x)放在 x 之前,并将所有较大的元素(大于 x)放在之后X。所有这些都应该在线性时间内完成。
快速排序优于归并排序,因为快速排序是一种就地算法(意味着不需要额外的内存空间)。
Java
// Java program for Quick Sort on Singly Linked List
public class QuickSortLinkedList
{
static class Node
{
int data;
Node next;
Node(int d)
{
this.data = d;
this.next= null;
}
}
Node head;
void addNode(int data)
{
if(head == null)
{
head = new Node(data);
return;
}
Node curr = head;
while(curr.next != null)
curr = curr.next;
Node newNode = new Node(data);
curr.next = newNode;
}
void printList(Node n)
{
while(n != null)
{
System.out.print(n.data);
System.out.print(" ");
n = n.next;
}
}
// takes first and last node,
// but do not break any links in
// the whole linked list
Node paritionLast(Node start, Node end)
{
if(start == end ||
start == null || end == null)
return start;
Node pivot_prev = start;
Node curr = start;
int pivot = end.data;
// iterate till one before the end,
// no need to iterate till the end
// because end is pivot
while(start != end )
{
if(start.data < pivot)
{
// keep tracks of last modified item
pivot_prev = curr;
int temp = curr.data;
curr.data = start.data;
start.data = temp;
curr = curr.next;
}
start = start.next;
}
// swap the position of curr i.e.
// next suitable index and pivot
int temp = curr.data;
curr.data = pivot;
end.data = temp;
// return one previous to current
// because current is now pointing to pivot
return pivot_prev;
}
void sort(Node start, Node end)
{
if(start == end )
return;
// split list and partion recurse
Node pivot_prev = paritionLast(start, end);
sort(start, pivot_prev);
// if pivot is picked and moved to the start,
// that means start and pivot is same
// so pick from next of pivot
if( pivot_prev != null &&
pivot_prev == start )
sort(pivot_prev.next, end);
// if pivot is in between of the list,
// start from next of pivot,
// since we have pivot_prev, so we move two nodes
else if(pivot_prev != null &&
pivot_prev.next != null)
sort(pivot_prev.next.next, end);
}
// Driver Code
public static void main(String[] args)
{
QuickSortLinkedList list = new QuickSortLinkedList();
list.addNode(8);
list.addNode(3);
list.addNode(7);
list.addNode(4);
Node n = list.head;
while(n.next != null)
n= n.next;
System.out.println("Original List: ");
list.printList(list.head);
list.sort(list.head , n);
System.out.println("\nSorted List: ");
list.printList(list.head);
}
}
Original List:
8 3 7 4
Sorted List:
3 4 7 8
时间复杂度: O(n ^ 2)
空间复杂度: O(1)
方法 3:使用归并排序进行排序
合并排序通常用于对链表进行排序。链表缓慢的随机访问性能使得其他一些算法(如快速排序)表现不佳,而其他算法(如堆排序)则完全不可能。
归并排序是一种分而治之的算法。它将输入数组分成两半,为两半调用自己,然后合并已排序的两半。 merge()函数用于合并两半。 merge(arr, l, m, r) 是一个关键过程,它假设 arr[l..m] 和 arr[m+1..r] 已排序并将两个已排序的子数组合并为一个。
- 设 head 是要排序的链表的第一个节点, headRef 是指向 head 的指针。
- 请注意,我们需要在 MergeSort() 中引用 head,因为下面的实现更改了 next 链接以对链表进行排序(不是节点处的数据),因此如果原始 head 的数据不是最小值,则必须更改头节点在链表中。
Java
// Java program to sort linkedList using Merge Sort
public class linkedList
{
node head = null;
// node a, b;
static class node {
int val;
node next;
public node(int val)
{
this.val = val;
}
}
node sortedMerge(node a, node b)
{
node result = null;
// Base cases
if (a == null)
return b;
if (b == null)
return a;
// Pick either a or b, and recur
if (a.val < b.val)
{
result = a;
result.next = sortedMerge(a.next, b);
}
else
{
result = b;
result.next = sortedMerge(a, b.next);
}
return result;
}
node mergeSort(node h)
{
// Base case : if head is null
if (h == null || h.next == null)
{
return h;
}
// get the middle of the list
node middle = getMiddle(h);
node nextofmiddle = middle.next;
// set the next of middle node to null
middle.next = null;
// Apply mergeSort on left list
node left = mergeSort(h);
// Apply mergeSort on right list
node right = mergeSort(nextofmiddle);
// Merge the left and right lists
node sortedlist = sortedMerge(left, right);
return sortedlist;
}
// Utility function to get the middle of the linked list
public static node getMiddle(node head)
{
if (head == null)
return head;
node slow = head, fast = head;
while (fast.next != null && fast.next.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
void push(int new_data)
{
// allocate node
node new_node = new node(new_data);
// link the old list off the new node
new_node.next = head;
// move the head to point to the new node
head = new_node;
}
// Utility function to print the linked list
void printList(node headref)
{
while (headref != null) {
System.out.print(headref.val + " ");
headref = headref.next;
}
}
public static void main(String[] args)
{
linkedList li = new linkedList();
li.push(4);
li.push(7);
li.push(3);
li.push(8);
System.out.print("\nOriginal List: \n");
li.printList(li.head);
// Apply merge Sort
li.head = li.mergeSort(li.head);
System.out.print("\nSorted List: \n");
li.printList(li.head);
}
}
Original List:
8 3 7 4
Sorted List:
3 4 7 8
时间复杂度: O(n log n)
空间复杂度: O(1)