数据结构七大排序及时间复杂度和空间复杂度的比较

1、插入排序

   主要思想:从第一个元素开始往后走,只不过每次比较从后往前比较。

   具体实现:记录走到的元素的值,给前面排好序的元素比较,遇见大的向后搬移,直到遇见小的,将该值放在小值的后面

void InsertSort(int array[], int size)
{
    for (int i = 0; i < size; i++){
        int last = array[i];
        int j;
        for (j = i - 1; j >= 0; j--){
            if (array[j] < last){
                break;
            }
            
            array[j + 1] = array[j];
        }
        array[j + 1] = last;
    }
}

2、希尔排序 

  主要思想:将元素按gap = (gap / 3) + 1(gap = size)的分配规则,分成gap份,每次将隔gap大小的元素进行比较排序

  具体实现:在直接插入排序的基础上,只不过每次给和gap相等数的元素个数,直到gap等于1

void InsertSortWithGap(int *array, int size, int gap)
{
    for(int i = gap; i < size; i++){
        int last = array[i];
        int j;
        for(j = i - gap; j >= 0; j -= gap){
            if(array[j] < last){
                break;
            }
            array[j + gap] = array[j];
        }
        array[j + gap] = last;
    }
}


void ShellSort(int *array, int size)
{
    int gap = size;
    while(gap != 1){
        gap = (gap / 3) + 1;
        InsertSortWithGap(array, size ,gap);
    }
}

3、冒泡排序

  主要思想:size个数只需要比较size-1次,每次将大的数向后移

  具体实现:两两相比,将最大的数往后移,循环一次,移动次数减一(因为后面的数已经是大数)

void BubbleSort(int *array, int size)
{
    for(int i = 1; i < size; i++){
        int count = 0;
        for(int j = 0; j < size - i; j++){
            if(array[j] > array[j + 1]){
                int tmp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = tmp;
                count++;
            }
        }
        if(count == 0){
            break;
        }
    }
}

 4、选择排序(找最大的)

  主要思想:每次选元素中的最大值,将其放在最后

  具体实现:假设一开始下标0是最大数的下标(max = 0),依次以后面的数进行比较,遇到大于其值的数时,将下标赋值给max,最后将最大值与size-i位置的数进行交换

void SelectSort(int *array, int size)
{
    for(int i = 1; i < size; i++){
        int max = 0;
        for(int j = 1; j <= size -i; j++){
            if(array[j] >= array[max]){
                max = j;
            }
        }
        //最大数在max下标下
        int tmp = array[max];
        array[max] = array[size - i];
        array[size - i] = tmp;
    }
}

升级版的选择排序(每次选出最大的和最小的)

void SelectSortOP(int *array, int size)
{
    int minSpace = 0;
    int maxSpace = size - 1;
    while(minSpace < maxSpace){
        int min = minSpace;
        int max = minSpace;
        for(int i = minSpace + 1; i <= maxSpace; i++){
            if(array[i] < array[min]){
                min = i;
            }
            if(array[i] > array[max]){
                max = i;
            }
        }
        
        int tmp1 = array[min];
        array[min] = array[minSpace];
        array[minSpace] = tmp1;
        
        if(max = minSpace){
            max = min;
        }

        int tmp2 = array[max];
        array[max] = array[maxSpace];
        array[maxSpace] = tmp2;

        minSpace++;
        maxSpace--;
    }
}

5.堆排序

//root表示要开始调整的结点下标
//建大堆
void AdjustDown(int *array, int size, int root)
{
	int left = 2 * root + 1;
	int right = 2 * root + 2;
	while (left < size){
		//找两个孩子中大的一个
		//只有一种情况,大的一个是右孩子
		//有右孩子并且右孩子的值大于左孩子的值
		int max = left;
		if (right < size && array[right]>array[left]){
			max = right;
		}

		if (array[root] >= array[max]){
			break;
		}

		int tmp = array[root];
		array[root] = array[max];
		array[max] = tmp;

		root = max;
		left = 2 * root + 1;
		right = 2 * root + 2;
	}
}

//建堆
void CreateHeap(int *array, int size)
{
	//从最后一个非叶子结点开始向下调整
	for (int i = (size - 2) / 2; i >= 0; i--){
		AdjustDown(array, size, i);
	}
}

//堆排序
//时间复杂度O(n*logn)
//空间复杂度O(1)
//不稳定
//数据不敏感
void HeapSort(int *array, int size)
{
	//建大堆
	CreateHeap(array, size);

	//选择
	for (int i = 1; i < size; i++){
		int tmp = array[0];
		array[0] = array[size - i];
		array[size - i] = tmp;

		AdjustDown(array, size - i, 0);
	}
}

6.快速排序

//快速排序
void Swap(int *a, int *b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//如何把小的放左、大的放右
//方法:1.hover
//不能保证left一定是0
int Partition_1(int array[], int left, int right) {
	int begin = left;    //不要写成begin = 0;
	int end = right;     //end不能是right - 1,反例{1, 2, 3, 4}
	while (begin < right&& end > left){
		//基准值在右边,先走左边
		//否则反例{1, 7, 8, 4}
		while (begin < right && array[begin] <= array[right]){
			begin++;
		}
		//意味着array[begin] > array[right]
		//{7,8,4}
		while (end > begin && array[end] >= array[right]){
			end--;
		}
		//意味着array[end] < array[right]

		Swap(array + begin, array + end);
	}
	//意味着区间本分为3份,分别是{小,大,基准值}
	Swap(array + begin, array + right);

	//返回当前基准值所在下标
	return begin;
}

//方法2:挖坑
int Partition_2(int array[], int left, int right) {
	int begin = left;
	int end = right;
	int pivot = array[right];
	//{1,4,2,3}
	while (begin < right && end > left){
		while (begin < right && array[begin] <= pivot){
			begin++;
		}
		array[end] = array[begin];

		while (end > begin && array[end] >= pivot){
			end--;
		}
		array[begin] = array[end];
	}
	array[begin] = pivot;

	return begin;
}

//方法3:前后下标
int Partition_3(int array[], int left, int right) {
	int div = left;  //div记录第一个比基准值大的数的下标
	for (int cur = left; cur < right; cur++){
		if (array[cur] < array[right]){
			//遇到有小于基准值的将小于基准值的数和div位置的值进行交换
			//div向后移一位
			Swap(array + cur, array + div);
			div++;
		}
	}
	Swap(array + div, array + right);

	return div;
}

//递归的方法
void _QuickSort(int array[], int left, int right) {
	//区间内只有一个数和区间内没有数
	if (left == right || left > right){
		return;
	}

	//基准值是array[right]
	int div;    //用来保存最终基准值所在的下标
	div = Partition_1(array, left, right);    //遍历array[left, right]
					          //把小的放左,大的放右
	                                          //返回最后基准值所在的下标
	//区间别分成三份:
	//[left, div - 1]比基准值小
	//[div ,div]基准值     已经在最终位置
	//[div + 1, right]比基准值大
	_QuickSort(array, left, div - 1);
	_QuickSort(array, div + 1, right);
}

//非递归的方法,用栈实现
//基本上所有的递归都可以使用栈来实现

void QuickSortNor(int array[], int size)
{
	std::stack  stack;
	stack.push(size - 1);   //right
	stack.push(0);          //left

	//判断栈中是否还有需要排序的范围
	while (!stack.empty()){
		int left = stack.top(); stack.pop();
		int right = stack.top(); stack.pop();

		//left>=right说明调用栈中的区间中没有元素或者元素只有一个
		if (left >= right){
			continue;
		}
		else{
			int div = Partition_1(array, left, right);

			//圧栈,根据你要先排序的顺序,先压右半部分,再压左半部分
			//排序顺序就是先左后右
			//[div+1,right]
			stack.push(right);
			stack.push(div + 1);

			//[left,div-1]
			stack.push(div - 1);
			stack.push(left);
		}
	}
}

//步骤:
//    1.选基准值
//		1>选最右(左)
//		2>三数取中:从最右、最左和中间这三个元素中随机选取一个作为基准值
//		3>随机:从数组中随机选取
//    2.Partition
//		1>Hover 2>挖坑 3>前后下标
//    3.分治算法,直到size <= 1
//		1>递归  2>非递归
//时间复杂度:O(n) * 二叉树的高度
//空间复杂度:二叉树的高度(O(log(n)) ~ O(n))
//稳定性:   不稳定
//快速排序
void QuickSort(int array[], int size) 
{
	_QuickSort(array, 0, size - 1);
	//QuickSortNor(array, size);
}

7.归并排序

//合并两个有序数组
void Merge(int array[], int left, int mid, int right, int *extra)
{
	int size = right - left;
	int left_index = left;
	int right_index = mid;
	int extra_index = 0;

	//判断左右元素的大小,将其按从小到大的顺序放在新空间extra中
	while (left_index < mid && right_index < right){
		if (array[left_index] <= array[right_index]){
			extra[extra_index] = array[left_index];
			left_index++;
		}
		else{
			extra[extra_index] = array[right_index];
			right_index++;
		}
		extra_index++;
	}

	//将剩余元素直接连接到extra的后面
	while (left_index < mid){
		extra[extra_index++] = array[left_index++];
	}

	while (right_index < right){
		extra[extra_index++] = array[right_index++];
	}

	//将extra中有序的元素,还原到原来数组中
	for (int i = 0; i < size; i++){
		array[left + i] = extra[i];
	}

	free(extra);
}

void _MergeSort(int array[], int left, int right, int* extra)
{
	//终止条件
	if (right <= left + 1){
		//区间内的数是小于等于1的
		return;
	}
	int mid = left + (right - left) / 2;
	//[left, mid) [mid, right)
	_MergeSort(array, left, mid, extra);
	_MergeSort(array, mid, right, extra);
	//左右区间都有序

	Merge(array, left, mid, right, extra);
}

//时间复杂度:最好|平均|最好   O(n*log(n))
//空间复杂度:O(n)
//稳定性:稳定的
//外部排序(支持大数据排序)
//归并排序(递归)
void MergeSort(int array[], int size) 
{
	int *extra = (int *)malloc(sizeof(int)*size);
	_MergeSort(array, 0, size, extra);
	free(extra);
}

//非递归
void MergeSortNor(int array[], int size)
{
	int *extra = (int *)malloc(sizeof(int) * size);
	for (int i = 1; i < size; i = i * 2){
		for (int j = 0; j < size; j = j + 2 * i){
			int left, mid, right;
			left = j;
			mid = j + i;
			right = mid + i;

			//走到最后mid已经是数组的大小
			if (mid >= size){
				//没有右边区间[mid, right)
				continue;
			}

			//最后一次排序的的有区间的范围应该是[mid, size)
			if (right > size){
				right = size;
			}

			Merge(array, left, mid, right, extra);
		}
	}
	free(extra);
}

七大排序相互比较:

数据结构七大排序及时间复杂度和空间复杂度的比较_第1张图片

 

你可能感兴趣的:(数据结构)