四种排序放发的应用场景

数据结构(下)–快速排序(三种优化),归并排序,堆排序,基数排序思想及代码实现
2019-03-31 10:09:28 chablin_ 阅读数 71 收藏 文章标签: 归并排序 堆排序 快速排序(三种优化) 基数排序
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chablin_/article/details/88924569
快速排序

思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序

时间复杂度:O(NlogN)

空间复杂度:O(1)
稳定性:不稳定

快速排序一共有三种:固定位置选取基准法(过程见下图)

随机选取基准法(基准选取不是arr[0],而是随机选取)

三分选取基准法(过程见下)

1.左中右三个数排序,并将中间数作为基准

2.将基准放到数组末尾(将基准与右端点前一个数交换)

3.从low向后查找第一个比tmp大的数,同时从high向前查找第一个比tmp小的数,两数交换(只找到9,此时9 6交换)

第一轮结束,此时6左边的数都小于它,右面的数都大于它,将数组分成两部分

接下来递归处理,对每一个子序列进行三位取中

算法优化:

1.如果排序的数据过少,直接插入法

2.聚集相同基准元素法 (一次划分后,把与par相等的元素聚在一起)
画图文字表述过程:

一趟快排过程:

tmp中存放arr[0],用low指针指向头,high指针指向尾

1.从high位置向前找第一个比tmp小的数,并与low所指位置交换,此时low向后走

2.low向后查找第一个比tmp大的数,并与之交换,此时high向前走

3.high向前查找第一个比tmp小的数,并与之交换,此时low向前走

4.low向后查找第一个比tmp大的数,并与之交换,此时high向前走

5.high向前查找第一个比tmp小的数,当low与high相遇时,一趟排序结束

一趟快排结束后,46左边的数都比46小,46右边的数都比它大,将这个数组以46为基准分成两部分,这两部分分别重复上述步骤排序

应用场景:大数据


int Partion(int *arr, int low, int high) //一趟快排,找基准
{
int tmp;
tmp = arr[low];
while (low <high)
{
while (low < high&&arr[high] >= tmp)
{
–high;
}
if (low>high)
{
break;
}
else
{
arr[low] = arr[high];
}
while (low < high&&arr[low] <= tmp)
{
low++;
}
if (low>high)
{
break;
}
else
{
arr[high] = arr[low];
}
arr[low] = tmp;
}
return low;
}
void QuickSort1(int *arr, int start, int end) //递归排序
{
int par;
if (start< end)
{
par = Partion(arr, start, end);
QuickSort1(arr, start, par - 1);
QuickSort1(arr, par + 1, end);
}
}

void QuickSort2(int *arr, int len) //非递归写法
{
int *stack = (int *)malloc(sizeof(int)*len);
assert(&stack != NULL);
int top = 0;
int low = 0;
int high = len - 1;
int par = Partion(arr, low, high);
stack[top++] = low;
stack[top++] = high;
while (top > 0)
{
high = stack[–top];
low = stack[–top];
if (low < high)
{
par = Partion(arr, low, high);
if (par - low > high - par)
{
stack[top++] = low;
stack[top++] = par - 1;
if (high > par)
{
stack[top++] = par + 1;
stack[top++] = high;
}
}
else
{
stack[top++] = par + 1;
stack[top++] = high;
if (par > low)
{
stack[top++] = low;
stack[top++] = par - 1;
}
}
}
}
}

void Swap(int *arr, int start, int end) //交换函数
{
int tmp = arr[start];
arr[start] = arr[end];
arr[end] = tmp;
}
void Focus_Same_Num(int *arr, int low, int par, int high, int *left, int *right) //聚集相同元素法
{
if (low < high)
{
int ParLeftIndex = par - 1;
int ParRightIndex = par + 1;
for (int i = par - 1; i >= low; i–)
{
if (arr[i] == arr[par])//如果两个值相等,那么交换,如果不是紧挨着的
{
if (i != ParLeftIndex)
{
Swap(arr, i, ParLeftIndex);//把相等的拉过来,聚集在一起
ParLeftIndex–;
}
else
{
ParLeftIndex–;
}

		}
	}
	*left = ParLeftIndex;

	for (int i = par + 1; i <= high; i++)
	{
		if (arr[i] == arr[par])
		{
			if (i != ParRightIndex)
			{
				Swap(arr, i, ParRightIndex);
				ParRightIndex++;
			}
			else
			{
				ParRightIndex++;
			}
		}
	}
	*right = ParRightIndex;
}

}
void Quick(int *arr, int low, int high)
{
if (low < high)
{
int par = Partion(arr, low, high);
int left = par - 1;
int right= par + 1;
//优化方式2:
Focus_Same_Num(arr, low, par, high, &left, &right);
//Qsort(arr,low,left);//分治左边序列
//Qsort(arr,right,high);//分治
printf(“par==%d\n”, par);
printf(“left==%d\n”, left);
printf(“right==%d\n”, right);
if (par > low + 1)
{
Quick(arr, low, left);//par-1
}
if (par < high - 1)
{
Quick(arr, right, high);par+1
}
}
}
void QuickSort(int *arr, int len)
{
Quick(arr, 0, len - 1);
}

归并排序

思想:分而治之

时间复杂度:O(NlogN)
空间复杂度:O(N)
稳定性:稳定
画图文字表述过程:不断的将原序列划分,直至两两一组,此时进行排序后再将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

应用场景:适用于总体无序,但各子项相对有序的数列

//归并排序:针对于外排(s1,e1;s2,e2,e1和e2不动,s1和s2走)
void Mearge(int *arr, int len, int gap)
{
int *brr = (int *)malloc(sizeof(int)*len);
assert(brr != NULL);
int i = 0;
int start1 = 0;
int end1 = start1 + gap - 1;
int start2 = end1 + 1;
int end2 = start2 + gap - 1<len - 1 ? start2 + gap - 1 : len - 1;
while (start2<len)//当前有两个归并段
{
while (start1 <= end1 && start2 <= end2)
{
if (arr[start1]<arr[start2])
{
brr[i++] = arr[start1++];
}
else
{
brr[i++] = arr[start2++];
}
}
while (start1 <= end1)
{
brr[i++] = arr[start1++];
}
while (start2 <= end2)
{
brr[i++] = arr[start2++];
}
start1 = end2 + 1;
end1 = start1 + gap - 1;
start2 = end1 + 1;
end2 = start2 + gap - 1>len - 1 ? start2 + gap - 1 : len - 1;
}
while (start1<len)
{
brr[i++] = arr[start1++];
}
for (int i = 0; i<len; i++)
{
arr[i] = brr[i];
}
free(brr);
brr = NULL;
}

void Mearge_Sort(int *arr, int len)
{
for (int i = 1; i<len; i *= 2)//2,4,8分段
{
Mearge(arr, len, i);
}
}
堆排序

思想:用大根堆排序

时间复杂度:O(NlogN)
空间复杂度:O(1) 稳定性:不稳定
画图文字表述过程:

12 34 45 21 4 6 33 54 15

从最后一颗枝丫从上往下调整

                大根堆

最后一个和第一个交换,此时54有序

调整第一颗枝丫

第一个与倒数第二个交换,此时45有序

调整第1 3颗枝丫,并使第一个与倒数第三个交换,此时34有序

应用场景:优先队列

void HeapAdjust(int *arr, int i, int len)
{
int Child = 2 * i + 1;
int tmp;
for (; 2 * i + 1 < len; i = Child)
{
if (Child < len - 1 && arr[Child + 1] > arr[Child])
{
++Child;
}
if (arr[i] < arr[Child])
{
tmp = arr[i];
arr[i] = arr[Child];
arr[Child] = tmp;
}
else
{
break;
}
}
}
void HeapSort(int *arr, int len)
{
int i, tmp = 0;
for (i = len / 2 - 1; i >= 0; --i)
{
HeapAdjust(arr, i, len);
}
for (i = len - 1; i > 0; --i)
{
tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
HeapAdjust(arr, 0, i);
}
}
基数排序

思想:先对每个数的最低位排序,分别入0-9号桶,再出桶,一直重复到对最高位排序

时间复杂度:O(N)
空间复杂度:O(K+N)
稳定性:稳定
画图文字表述过程:

310 100 222 4410 20 3 952 774 18

出桶:310 100 4410 20 222 952 3 774 18

出桶:100 3 310 4410 18 20 222 952 774

出桶:3 18 20 100 222 310 4410 774 952

出桶:3 18 20 100 222 310 774 952 4410

应用场景:适用于位数少的数列

typedef struct Node
{
int data;
struct Node*next;
}Node, *List;

void InitList(List plist)
{
assert(plist != NULL);
plist->next = NULL;
}

static Node *GetNode(int val)
{
Node *pGet = (Node *)malloc(sizeof(Node));
assert(pGet != NULL);
pGet->data = val;
pGet->next = NULL;
return pGet;
}
bool Insert_tail(List plist, int val)
{
assert(plist != NULL);
Node p;
for (p = plist; p->next != NULL; p = p->next)
{
;
}
Node pGet = GetNode(val);
p->next = pGet;
return true;
}
bool DelFirst(List plist, int
rtv)
{
assert(plist != NULL);
Node
p = plist->next;
if (plist->next == NULL)
{
return false;
}
if (rtv != NULL)
{
*rtv = p->data;
}
plist->next = p->next;
free§;
p = NULL;
return true;
}
int GetMaxBit(int *arr, int len)//得到数组里数的最高位
{
assert(arr != NULL);
int max = 0;
for (int i = 0; i < len; i++)
{
if (arr[i] > arr[max])
{
arr[max] = arr[i];
}
}
int count = 0;
while (arr[max] != 0)
{
count++;
arr[max] /= 10;
}
return count;
}
int GetNum(int num, int figure)//得到num第figure位数字
{
for (int i = 0; i < figure; i++)
{
num /= 10;
}
return num % 10;
}
void Radix(int *arr, int len, int figure)//入桶出桶操作
{
assert(arr != NULL);
Node head[10];
int i;
for (i = 0; i < 10; i++)
{
InitList(&head[i]);
}
//入桶
int tmp;
for (i = 0; i < len; i++)
{
tmp = GetNum(arr[i], figure);
Insert_tail(&head[tmp], arr[i]);
}
//出桶
i = 0;
for (int j = 0; j < 10; )
{
if (DelFirst(&head[j], &arr[i]))//桶内有数据,则出成功
{
i++;
}
else
{
j++;//桶内没数据,就便历下一个桶
}
}
}
void Radix_Sort(int *arr, int len)//基数排序
{
assert(arr != NULL);
int count = GetMaxBit(arr, len);
for (int i = 0; i < count; i++)
{
Radix(arr, len, i);
}
}
void show(int *arr, int len)
{
for (int i = 0; i < len; ++i)
{
printf("%d “, arr[i]);
}
printf(”\n");
}
数据结构(下)–快速排序(三种优化),归并排序,堆排序,基数排序思想及代码实现
2019-03-31 10:09:28 chablin_ 阅读数 71 收藏 文章标签: 归并排序 堆排序 快速排序(三种优化) 基数排序
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chablin_/article/details/88924569
快速排序

思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序

时间复杂度:O(NlogN)

空间复杂度:O(1)
稳定性:不稳定

快速排序一共有三种:固定位置选取基准法(过程见下图)

随机选取基准法(基准选取不是arr[0],而是随机选取)

三分选取基准法(过程见下)

1.左中右三个数排序,并将中间数作为基准

2.将基准放到数组末尾(将基准与右端点前一个数交换)

3.从low向后查找第一个比tmp大的数,同时从high向前查找第一个比tmp小的数,两数交换(只找到9,此时9 6交换)

第一轮结束,此时6左边的数都小于它,右面的数都大于它,将数组分成两部分

接下来递归处理,对每一个子序列进行三位取中

算法优化:

1.如果排序的数据过少,直接插入法

2.聚集相同基准元素法 (一次划分后,把与par相等的元素聚在一起)
画图文字表述过程:

一趟快排过程:

tmp中存放arr[0],用low指针指向头,high指针指向尾

1.从high位置向前找第一个比tmp小的数,并与low所指位置交换,此时low向后走

2.low向后查找第一个比tmp大的数,并与之交换,此时high向前走

3.high向前查找第一个比tmp小的数,并与之交换,此时low向前走

4.low向后查找第一个比tmp大的数,并与之交换,此时high向前走

5.high向前查找第一个比tmp小的数,当low与high相遇时,一趟排序结束

一趟快排结束后,46左边的数都比46小,46右边的数都比它大,将这个数组以46为基准分成两部分,这两部分分别重复上述步骤排序

应用场景:大数据


int Partion(int *arr, int low, int high) //一趟快排,找基准
{
int tmp;
tmp = arr[low];
while (low <high)
{
while (low < high&&arr[high] >= tmp)
{
–high;
}
if (low>high)
{
break;
}
else
{
arr[low] = arr[high];
}
while (low < high&&arr[low] <= tmp)
{
low++;
}
if (low>high)
{
break;
}
else
{
arr[high] = arr[low];
}
arr[low] = tmp;
}
return low;
}
void QuickSort1(int *arr, int start, int end) //递归排序
{
int par;
if (start< end)
{
par = Partion(arr, start, end);
QuickSort1(arr, start, par - 1);
QuickSort1(arr, par + 1, end);
}
}

void QuickSort2(int *arr, int len) //非递归写法
{
int *stack = (int *)malloc(sizeof(int)*len);
assert(&stack != NULL);
int top = 0;
int low = 0;
int high = len - 1;
int par = Partion(arr, low, high);
stack[top++] = low;
stack[top++] = high;
while (top > 0)
{
high = stack[–top];
low = stack[–top];
if (low < high)
{
par = Partion(arr, low, high);
if (par - low > high - par)
{
stack[top++] = low;
stack[top++] = par - 1;
if (high > par)
{
stack[top++] = par + 1;
stack[top++] = high;
}
}
else
{
stack[top++] = par + 1;
stack[top++] = high;
if (par > low)
{
stack[top++] = low;
stack[top++] = par - 1;
}
}
}
}
}

void Swap(int *arr, int start, int end) //交换函数
{
int tmp = arr[start];
arr[start] = arr[end];
arr[end] = tmp;
}
void Focus_Same_Num(int *arr, int low, int par, int high, int *left, int *right) //聚集相同元素法
{
if (low < high)
{
int ParLeftIndex = par - 1;
int ParRightIndex = par + 1;
for (int i = par - 1; i >= low; i–)
{
if (arr[i] == arr[par])//如果两个值相等,那么交换,如果不是紧挨着的
{
if (i != ParLeftIndex)
{
Swap(arr, i, ParLeftIndex);//把相等的拉过来,聚集在一起
ParLeftIndex–;
}
else
{
ParLeftIndex–;
}

		}
	}
	*left = ParLeftIndex;

	for (int i = par + 1; i <= high; i++)
	{
		if (arr[i] == arr[par])
		{
			if (i != ParRightIndex)
			{
				Swap(arr, i, ParRightIndex);
				ParRightIndex++;
			}
			else
			{
				ParRightIndex++;
			}
		}
	}
	*right = ParRightIndex;
}

}
void Quick(int *arr, int low, int high)
{
if (low < high)
{
int par = Partion(arr, low, high);
int left = par - 1;
int right= par + 1;
//优化方式2:
Focus_Same_Num(arr, low, par, high, &left, &right);
//Qsort(arr,low,left);//分治左边序列
//Qsort(arr,right,high);//分治
printf(“par==%d\n”, par);
printf(“left==%d\n”, left);
printf(“right==%d\n”, right);
if (par > low + 1)
{
Quick(arr, low, left);//par-1
}
if (par < high - 1)
{
Quick(arr, right, high);par+1
}
}
}
void QuickSort(int *arr, int len)
{
Quick(arr, 0, len - 1);
}

归并排序

思想:分而治之

时间复杂度:O(NlogN)
空间复杂度:O(N)
稳定性:稳定
画图文字表述过程:不断的将原序列划分,直至两两一组,此时进行排序后再将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

应用场景:适用于总体无序,但各子项相对有序的数列

//归并排序:针对于外排(s1,e1;s2,e2,e1和e2不动,s1和s2走)
void Mearge(int *arr, int len, int gap)
{
int *brr = (int *)malloc(sizeof(int)*len);
assert(brr != NULL);
int i = 0;
int start1 = 0;
int end1 = start1 + gap - 1;
int start2 = end1 + 1;
int end2 = start2 + gap - 1<len - 1 ? start2 + gap - 1 : len - 1;
while (start2<len)//当前有两个归并段
{
while (start1 <= end1 && start2 <= end2)
{
if (arr[start1]<arr[start2])
{
brr[i++] = arr[start1++];
}
else
{
brr[i++] = arr[start2++];
}
}
while (start1 <= end1)
{
brr[i++] = arr[start1++];
}
while (start2 <= end2)
{
brr[i++] = arr[start2++];
}
start1 = end2 + 1;
end1 = start1 + gap - 1;
start2 = end1 + 1;
end2 = start2 + gap - 1>len - 1 ? start2 + gap - 1 : len - 1;
}
while (start1<len)
{
brr[i++] = arr[start1++];
}
for (int i = 0; i<len; i++)
{
arr[i] = brr[i];
}
free(brr);
brr = NULL;
}

void Mearge_Sort(int *arr, int len)
{
for (int i = 1; i<len; i *= 2)//2,4,8分段
{
Mearge(arr, len, i);
}
}
堆排序

思想:用大根堆排序

时间复杂度:O(NlogN)
空间复杂度:O(1) 稳定性:不稳定
画图文字表述过程:

12 34 45 21 4 6 33 54 15

从最后一颗枝丫从上往下调整

                大根堆

最后一个和第一个交换,此时54有序

调整第一颗枝丫

第一个与倒数第二个交换,此时45有序

调整第1 3颗枝丫,并使第一个与倒数第三个交换,此时34有序

应用场景:优先队列

void HeapAdjust(int *arr, int i, int len)
{
int Child = 2 * i + 1;
int tmp;
for (; 2 * i + 1 < len; i = Child)
{
if (Child < len - 1 && arr[Child + 1] > arr[Child])
{
++Child;
}
if (arr[i] < arr[Child])
{
tmp = arr[i];
arr[i] = arr[Child];
arr[Child] = tmp;
}
else
{
break;
}
}
}
void HeapSort(int *arr, int len)
{
int i, tmp = 0;
for (i = len / 2 - 1; i >= 0; --i)
{
HeapAdjust(arr, i, len);
}
for (i = len - 1; i > 0; --i)
{
tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
HeapAdjust(arr, 0, i);
}
}
基数排序

思想:先对每个数的最低位排序,分别入0-9号桶,再出桶,一直重复到对最高位排序

时间复杂度:O(N)
空间复杂度:O(K+N)
稳定性:稳定
画图文字表述过程:

310 100 222 4410 20 3 952 774 18

出桶:310 100 4410 20 222 952 3 774 18

出桶:100 3 310 4410 18 20 222 952 774

出桶:3 18 20 100 222 310 4410 774 952

出桶:3 18 20 100 222 310 774 952 4410

应用场景:适用于位数少的数列

typedef struct Node
{
int data;
struct Node*next;
}Node, *List;

void InitList(List plist)
{
assert(plist != NULL);
plist->next = NULL;
}

static Node *GetNode(int val)
{
Node *pGet = (Node *)malloc(sizeof(Node));
assert(pGet != NULL);
pGet->data = val;
pGet->next = NULL;
return pGet;
}
bool Insert_tail(List plist, int val)
{
assert(plist != NULL);
Node p;
for (p = plist; p->next != NULL; p = p->next)
{
;
}
Node pGet = GetNode(val);
p->next = pGet;
return true;
}
bool DelFirst(List plist, int
rtv)
{
assert(plist != NULL);
Node
p = plist->next;
if (plist->next == NULL)
{
return false;
}
if (rtv != NULL)
{
*rtv = p->data;
}
plist->next = p->next;
free§;
p = NULL;
return true;
}
int GetMaxBit(int *arr, int len)//得到数组里数的最高位
{
assert(arr != NULL);
int max = 0;
for (int i = 0; i < len; i++)
{
if (arr[i] > arr[max])
{
arr[max] = arr[i];
}
}
int count = 0;
while (arr[max] != 0)
{
count++;
arr[max] /= 10;
}
return count;
}
int GetNum(int num, int figure)//得到num第figure位数字
{
for (int i = 0; i < figure; i++)
{
num /= 10;
}
return num % 10;
}
void Radix(int *arr, int len, int figure)//入桶出桶操作
{
assert(arr != NULL);
Node head[10];
int i;
for (i = 0; i < 10; i++)
{
InitList(&head[i]);
}
//入桶
int tmp;
for (i = 0; i < len; i++)
{
tmp = GetNum(arr[i], figure);
Insert_tail(&head[tmp], arr[i]);
}
//出桶
i = 0;
for (int j = 0; j < 10; )
{
if (DelFirst(&head[j], &arr[i]))//桶内有数据,则出成功
{
i++;
}
else
{
j++;//桶内没数据,就便历下一个桶
}
}
}
void Radix_Sort(int *arr, int len)//基数排序
{
assert(arr != NULL);
int count = GetMaxBit(arr, len);
for (int i = 0; i < count; i++)
{
Radix(arr, len, i);
}
}
void show(int *arr, int len)
{
for (int i = 0; i < len; ++i)
{
printf("%d “, arr[i]);
}
printf(”\n");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值