链表是一个线性数据结构,其中的元素是不能存储在连续的存储单元。
按升序对单链接列表的节点进行排序:
![原始清单](https://mangdo-1254073825.cos.ap-chengdu.myqcloud.com//front_eng_imgs/geeksforgeeks2021/How%20to%20Sort%20a%20LinkedList%20in%20Java?_0.jpg)
原始清单
![SortedList](https://mangdo-1254073825.cos.ap-chengdu.myqcloud.com//front_eng_imgs/geeksforgeeks2021/How%20to%20Sort%20a%20LinkedList%20in%20Java?_1.jpg)
排序清单
我们可以通过许多排序技术对LinkedList进行排序:
- 气泡排序
- 插入排序
- 快速分类
- 合并排序
方法1:使用冒泡排序进行排序
- 为了完成此任务,我们维护两个指针:current和index。
- 最初,当前指向头节点,索引将指向当前旁边的节点。
- 通过将当前数据与索引数据进行比较,遍历列表直到当前指向null。
- 对于每个当前值,索引是当前节点的下一个节点,它从当前的下一个节点开始遍历直到为空。
- 然后,将当前节点的值与从其下一个节点到最后一个节点的每个值进行比较,如果该值小于当前值,则将交换这些值,并以这种方式将最小值作为当前索引。
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:使用合并排序
合并排序通常是对链表进行排序的首选。链表的随机访问性能较慢,使得其他一些算法(例如quicksort)的性能较差,而其他算法(例如堆排序)则完全不可能。
合并排序是一种分而治之算法。它将输入数组分为两个半部分,将自身称为两个半部分,然后合并两个已排序的半个部分。 merge()函数用于合并两个半部分。 merge(arr,l,m,r)是一个关键过程,假定对arr [l..m]和arr [m + 1..r]进行排序并将两个排序后的子数组合并为一个。
- 令head是要排序的链表的第一个节点,而headRef是指向head的指针。
- 请注意,我们需要在MergeSort()中引用head,因为以下实现会更改下一个链接以对链接列表进行排序(而不是节点上的数据),因此,如果原始head上的数据不是最小值,则必须更改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)