【编程4】插入排序+快速排序+LeetCode.148(排序链表)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012736685/article/details/84964315

一、排序链表

1、题目描述——LeetCode.148

在 O(n logn) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

2、分析

本实现采用快速排序算法实现

(1)一般的快排

需要一个指针指向头,一个指针指向尾,然后两个指针相向运动并按一定规律交换值,最后找到一个支点使得支点左边小于支点,支点右边大于支点
==》如果是这样的话,对于单链表我们没有前驱指针,怎么能使得后面的那个指针往前移动呢?
==》使两个指针都往next方向移动并且能找到支点那就好了。

(2)解题思路

只需要两个指针p和q,这两个指针均往next方向移动,移动的过程中保持p之前的key都小于选定的key,p和q之间的key都大于选定的key,那么当q走到末尾的时候便完成了一次支点的寻找。

3、实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == NULL)
            return NULL;
        ListNode *right = head;
        while(right->next)
            right = right->next;
        QuickSort(head, right);
        return head;
    }
private:
    void QuickSort(ListNode *left, ListNode *right)
    {
        if(left != right)
        {
            ListNode *partion = GetPartion(left, right);
            QuickSort(left, partion);
            if(partion->next)
                QuickSort(partion->next, right);
        }
    }
    ListNode *GetPartion(ListNode *left, ListNode *right)
    {
        int key = left->val;
        ListNode *p = left;
        ListNode *q = p->next;
        
        while(q != right->next)
        {
            if(q->val < key)
            {
                p = p->next;
                swap(p->val, q->val);
            }
            q = q->next;
        }
        swap(p->val, left->val);
        return p;
    }
};

在这里插入图片描述

二、排序算法

排序方法 时间复杂度 是否基于比较 适用性
1 冒泡、插入、选择 O(n2) 适合小规模数据排序
2 快排、归并 O(nlogn) 适合大规模的数据排序
3 桶、计数、基数 O(n) ×

三、插入排序

1、基本思想

将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。

(1)过程概述

插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

(2)具体算法描述:

① 从第一个元素开始,该元素可以认为已经被排序;
② 取出下一个元素,在已经排序的元素序列中从后向前扫描;
③ 如果该元素(已排序)大于新元素,将该元素移到下一位置;
④ 重复步骤 ③,直到找到已排序的元素小于或者等于新元素的位置;
⑤ 将新元素插入到该位置后
⑥ 重复步骤②~⑤

2、示例

原数据:{4,5,6,1,3,2}
排序过程:其中左侧是已排序区间,右侧是未排序区间。
在这里插入图片描述

3、实现

void insertSort(int a[], int len){
	int tmp, j;
	for(int i = 1; i < len; i++){
		tmp = a[i];
		int j = i - 1;
		while(tmp < a[j])
		{
			a[j + 1] = a[j];
			j--;
		}
		a[j + 1] = tmp;
	}
}

4、分析

(1)原地排序算法

  • 空间复杂度为 O(1)
    ==》原地排序算法

(2)稳定排序算法

  • 对于值相同的元素,可以选择将后面出现的元素,插入到前面出现元素的后面。
    ==》保持原有前后顺序,也就是稳定的排序算法

(3)时间复杂度

  • 最好情况时间复杂度(数据已经有序):O(n)
  • 最坏情况时间复杂度:O(n2)
  • 平均时间复杂度:O(n2)
    • 对于插入排序来说,每次插入操作(时间复杂度为O(n))都相当于在数组中插入一个数据,循环执行 n 次插入操作

四、快速排序

1、基本思想

基于分治思想快速排序算法:选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

(1)快速排序的流程

① 从数列中挑出一个基准值(枢轴,pivot)。
② 将数组进行划分(partition),将比基准数大的元素都移至枢轴右边,将小于等于基准数的元素都移至枢轴左边。在这个分区退出之后,该基准就处于数列的中间位置。
③ 递归地把"基准值前面的子数列"和"基准值后面的子数列"进行排序。

2、实现

  • 实现一
    将第一个元素设置为基准值来划分区间,基准值的位置始终不变,最后交换使得基准值的位置。
// left、right分别表示要交换数组的第一个元素和最后一个元素的位置
int partition(int arr[], int left, int right)
{
	int i = left + 1;
	int j = right;
	// 将第一个元素设置为 基准值
	int temp = arr[left];

	while(i <= j)
	{
		while(arr[i] < temp)
			i++;
		while(arr[j] > temp)
			j--;
		if(i < j)
			swap(arr[i++], arr[j--]);
		else
			i++;
	}
	swap(arr[j], arr[left]);
	return j;
}
void quick_sort(int arr[], int left, int right)
{
	if(left > right)
		return;
	int j = partition(arr, left, right);
	quick_sort(arr, left, j - 1);
	quick_sort(arr, j + 1, right);
}
  • 实现二
    将第一个元素设置为基准值来划分区间,将基准值不断与冲突值进行换位。
void QuickSort(int arr[], int left, int right)
{
	int i = left;
	int j = right;
	int temp = arr[i];
	if(i < j)
	{
		while(i < j)
		{
			while(i < j && arr[j] >= temp)
				j--;
			if(i < j)
			{
				arr[i] = arr[j];
				i++;
			}
			while(i < j && arr[i] < temp)
				i++;
			if(i < j)
			{
				arr[j] = arr[i];
				j--;
			}
		}
		// 将基准数放在 i 位置
		arr[i] = temp;
		// 递归实现
		QuickSort(arr, left, i - 1);
		QuickSort(arr, i + 1, right);
	}
}

3、性能分析

  • 不稳定
  • 原地排序——空间复杂度为O(1)
  • 时间复杂度:大部分情况下的时间复杂度都可以做到 O(nlogn),只有在极端情况下,才会退化到 O(n2)。

猜你喜欢

转载自blog.csdn.net/u012736685/article/details/84964315