数据结构实验四 Radix Sort And Stack
Posted fanlumaster
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构实验四 Radix Sort And Stack相关的知识,希望对你有一定的参考价值。
一、实验描述
-
Radix Sort。实现桶式排序和基于桶式排序的基数排序。在基数 B 中,数组长度 n 和 最大元素 m 中,对排序时间影响最大的是哪一个?元素在未排序数组中的顺序是否对时间复杂度有影响?设计实验证明你的想法。
-
Stack。用 C 语言设计堆栈,并实现中缀表达式到后缀表达式的转换。
二、问题分析与算法设计
1、Radix Sort
-
对于桶排序,其算法实现为:使用一个大小为 (M) 的名为 (Count) 的数组,它被初始化为全部为 0.于是,(Count) 有 (M) 个单元(即桶),这些桶初始化为空。当读入 (A_i) ((A_1, A_2..., A_N) 为小于 (M) 的输入数据,且为正整数),(Count[A_i]) 增 1。在所有的输入数据读入后,扫描数组 (Count),打印出排序后的数组。
-
对于基数排序,其算法实现为:将整数按位数切割成不同的数字,然后按每个位数分别比较。具体操作是将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
2、中缀表达式转后缀表达式
算法主要利用堆栈,算法实现为:
从头到尾读取中缀表达式中的每个对象,对不同对象按不同的情况处理。
- Ⅰ 运算数:直接输出
- Ⅱ 左括号:压入堆栈
- Ⅲ 右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
- Ⅳ 运算符:
- 若优先级大于栈顶运算符时,则将它压栈
- 若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈
- Ⅴ 若各对象处理完毕,则把堆栈中存留的运算符一并输出。
三、算法实现
1、Radix Sort
1.1、桶式排序
/**
* 桶式排序
* @param A 待排序数组
* @param m 最大元素
* @param n 数组长度
*/
void BucketSort(int *A, int m, int n)
{
int B[m + 1];
int i, j, count = 0;
memset(B, 0, (m + 1) * sizeof(int)); // 数组初始化
for (i = 0; i < n; i++)
{
j = A[i];
B[j] += 1; // 记录该桶中元素个数
}
// 把桶中的元素按顺序依次放入原数组中
for (i = 0; i <= m; i++)
{
if (B[i] > 0) // 该桶不为空
{
for (j = 0; j < B[i]; j++)
{
A[count] = i;
count++;
}
}
}
}
1.2、基数排序
/**
* 利用计数排序的基数排序
* @param A 待排数组
* @param n 数组元素个数
*/
void RadixSort(int *A, int n)
{
int exp; // 指数,当对数组按照个位数进行排序时,exp = 1,按十位数排序时,exp = 10...
int max = 0;
// 获取数组最大值
for (int i = 0; i < n; i++)
{
if (A[i] > max)
max = A[i];
}
// 从个位数开始,对数组进行按位排序
for (exp = 1; max / exp > 0; exp *= 10)
{
int tmp[n]; // 存储“被排序数据”的临时数组
int i, buckets[10];
memset(buckets, 0, 10 * sizeof(int)); // 数组初始化为 0
// 存储数据出现的次数
for (i = 0; i < n; i++)
buckets[(A[i] / exp) % 10]++;
// 将 buckets[i] 更新为前面所有元素的个数之和,即,buckets[i] 中存储的是其对应的数据在 tmp[] 中的位置,即最终此趟排序下来后数据在 A[] 中的位置
for (i = 1; i < 10; i++)
buckets[i] += buckets[i - 1];
// 将数据存储到临时数组 tmp[] 中
for (i = n - 1; i >= 0; i--)
tmp[--buckets[(A[i] / exp) % 10]] = A[i];
// 将排好的数据赋值给 A[]
for (i = 0; i < n; i++)
A[i] = tmp[i];
}
}
2、中缀表达式转后缀表达式
// 获取字符的优先值
int Priority(char op)
{
int priority;
if (op == ‘*‘ || op == ‘/‘)
priority = 2;
if (op == ‘+‘ || op == ‘-‘)
priority = 1;
if (op == ‘(‘)
priority = 0;
return priority;
}
bool TransEX(char *str, char * str1)
{
Stack S = CreateStack();
int i, j = 0;
for (i = 0; str[i] != ‘#‘; i++)
{
if ((str[i] >= ‘0‘ && str[i] <= ‘9‘) || (str[i] >= ‘a‘ && str[i] <= ‘z‘)) // 数字或者字母直接入栈
str1[j++] = str[i];
else // 不是数字或者字母
{
if (IsEmpty(S)) // 栈空则入栈
Push(str[i], S);
else if (str[i] == ‘(‘) // 左括号入栈
Push(str[i], S);
else if (str[i] == ‘)‘) // 如果是右括号,只要栈顶不是左括号,就弹出并输出
{
while (Top(S) != ‘(‘)
{
str1[j++] = Top(S);
Pop(S);
}
Pop(S); // 弹出左括号
}
else
{
while (Priority(str[i]) <= Priority(Top(S))) // 栈顶优先级大于等于当前运算符,则输出
{
str1[j++] = Top(S);
Pop(S);
if (IsEmpty(S))
break;
}
Push(str[i], S); // 把当前运算符压栈
}
}
}
while (!IsEmpty(S))
{
str1[j++] = Top(S);
Pop(S);
}
str1[j] = ‘#‘;
DisposeStack(S);
return true;
}
四、实验结果
1、Radix Sort
1.1、桶式排序
1.2、基数排序
2、中缀表达式转后缀表达式
五、复杂度分析
1、Radix Sort
1.1、桶式排序
原数组的长度为 (N),所以需要扫描 (N) 次,之后在重新赋值给原数组时,又对 (M) 只桶进行了扫描,因此,总的时间复杂度为 (O(M + N))。
1.2、基数排序
基数排序中主要为一个二重循环,其中,外层循环的次数是待排序数字中最大值的位数,内层有四个时间复杂度为 (O(n)) 的一重循环,其总体可以看成 (O(n)),因此,基数排序的时间复杂度为 (O(k · n)),其中 (n) 是待排序元素的个数,(k) 是数字的位数。
2、中缀表达式转后缀表达式
从算法的实现中,我们可以看出其时间复杂度是线性的,每一次循环处理一个字符,因此其时间复杂度为 (O(N))。
六、实验结论
- Ⅰ因为最大数的位数是指数级的,基数 (B) 的选择对结果影响不是太大,因此数组的长度 (n) 对排序的时间影响最大。
- Ⅱ基数排序并非基于比较的排序,因此改变元素次序不会对时间复杂度产生影响。
根据实验结果,可以证明上面的分析的正确性。
七、附:完整代码
1、Radix Sort
#include <stdio.h>
#include "string.h"
/**
* 桶式排序
* @param A 待排序数组
* @param m 最大元素
* @param n 数组长度
*/
void BucketSort(int *A, int m, int n)
{
int B[m + 1];
int i, j, count = 0;
memset(B, 0, (m + 1) * sizeof(int)); // 数组初始化
for (i = 0; i < n; i++)
{
j = A[i];
B[j] += 1; // 记录该桶中元素个数
}
// 把桶中的元素按顺序依次放入原数组中
for (i = 0; i <= m; i++)
{
if (B[i] > 0) // 该桶不为空
{
for (j = 0; j < B[i]; j++)
{
A[count] = i;
count++;
}
}
}
}
/**
* 利用计数排序的基数排序
* @param A 待排数组
* @param n 数组元素个数
*/
void RadixSort(int *A, int n)
{
int exp; // 指数,当对数组按照个位数进行排序时,exp = 1,按十位数排序时,exp = 10...
int max = 0;
// 获取数组最大值
for (int i = 0; i < n; i++)
{
if (A[i] > max)
max = A[i];
}
// 从个位数开始,对数组进行按位排序
for (exp = 1; max / exp > 0; exp *= 10)
{
int tmp[n]; // 存储“被排序数据”的临时数组
int i, buckets[10];
memset(buckets, 0, 10 * sizeof(int)); // 数组初始化为 0
// 存储数据出现的次数
for (i = 0; i < n; i++)
buckets[(A[i] / exp) % 10]++;
// 将 buckets[i] 更新为前面所有元素的个数之和,即,buckets[i] 中存储的是其对应的数据在 tmp[] 中的位置,即最终此趟排序下来后数据在 A[] 中的位置
for (i = 1; i < 10; i++)
buckets[i] += buckets[i - 1];
// 将数据存储到临时数组 tmp[] 中
for (i = n - 1; i >= 0; i--)
tmp[--buckets[(A[i] / exp) % 10]] = A[i];
// 将排好的数据赋值给 A[]
for (i = 0; i < n; i++)
A[i] = tmp[i];
}
}
int main()
{
int i;
// 桶式排序测试
int a0[10] = {7,8,5,4,1,6,12,14,10,11};
printf("桶式排序 Before sort:
");
for (i = 0; i < 10; i++)
printf("%d ", a0[i]);
printf("
");
BucketSort(a0, 54, 10);
printf("桶式排序 After sort:
");
for (i = 0; i < 10; i++)
printf("%d ", a0[i]);
printf("
");
printf("-----------------------
");
// 基数排序测试
int a[10] = {64,8,216,512,27,729,0,1,343,125};
printf("基数排序 Before sort:
");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("
");
RadixSort(a, 10);
printf("基数排序 After sort:
");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("
");
return 0;
}
2、中缀表达式转后缀表达式
2.1、main.c
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#include "stdbool.h"
// 获取字符的优先值
int Priority(char op)
{
int priority;
if (op == ‘*‘ || op == ‘/‘)
priority = 2;
if (op == ‘+‘ || op == ‘-‘)
priority = 1;
if (op == ‘(‘)
priority = 0;
return priority;
}
bool TransEX(char *str, char * str1)
{
Stack S = CreateStack();
int i, j = 0;
for (i = 0; str[i] != ‘#‘; i++)
{
if ((str[i] >= ‘0‘ && str[i] <= ‘9‘) || (str[i] >= ‘a‘ && str[i] <= ‘z‘)) // 数字或者字母直接入栈
str1[j++] = str[i];
else // 不是数字或者字母
{
if (IsEmpty(S)) // 栈空则入栈
Push(str[i], S);
else if (str[i] == ‘(‘) // 左括号入栈
Push(str[i], S);
else if (str[i] == ‘)‘) // 如果是右括号,只要栈顶不是左括号,就弹出并输出
{
while (Top(S) != ‘(‘)
{
str1[j++] = Top(S);
Pop(S);
}
Pop(S); // 弹出左括号
}
else
{
while (Priority(str[i]) <= Priority(Top(S))) // 栈顶优先级大于等于当前运算符,则输出
{
str1[j++] = Top(S);
Pop(S);
if (IsEmpty(S))
break;
}
Push(str[i], S); // 把当前运算符压栈
}
}
}
while (!IsEmpty(S))
{
str1[j++] = Top(S);
Pop(S);
}
str1[j] = ‘#‘;
DisposeStack(S);
return true;
}
int main()
{
char *infix = malloc(20 * sizeof(char));
char *postfix = malloc(20 * sizeof(char));
printf("请输入中缀表达式(以 “#” 结束):
");
fflush(stdout);
scanf("%s", infix);
TransEX(infix, postfix);
printf("后缀表达式为:
");
// 打印转换好的字符串
for (int i = 0; postfix[i] != ‘#‘ ; i++)
{
printf("%c", postfix[i]);
}
return 0;
}
2.2、stack.h
typedef char ElementType;
#ifndef _Stack_h
#define _Stack_h
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode Stack;
int IsEmpty(Stack S);
Stack CreateStack(void);
void DisposeStack(Stack S);
void MakeEmpty(Stack S);
void Push(ElementType X, Stack S);
ElementType Top(Stack S);
void Pop(Stack S);
ElementType TopAndPop(Stack S);
#endif
2.3、stack.c
#include "stack.h"
#include "fatal.h"
#include <stdlib.h>
// 节点
struct Node
{
ElementType Element;
PtrToNode Next;
};
// 判断栈是否为空,判断方法为判断头节点S指向的下一个节点是否为空
int
IsEmpty(Stack S)
{
return S->Next == NULL;
}
// 创建一个栈,主要是创建一个头节点
Stack
CreateStack(void)
{
Stack S;
S = malloc(sizeof(struct Node));
if (S == NULL)
FatalError("Out of space!!!"); // 空间用尽警告
S->Next = NULL;
MakeEmpty(S);
return S;
}
// 创建一个空栈
void
MakeEmpty(Stack S)
{
if (S == NULL)
Error("Must use CreateStack first");
else
while (!IsEmpty(S))
Pop(S);
}
// 处理掉这个栈,即清空所有元素并释放头节点
void
DisposeStack(Stack S)
{
MakeEmpty(S);
free(S);
}
// 进栈操作
void
Push(ElementType X, Stack S)
{
PtrToNode TmpCell;
TmpCell = malloc(sizeof(struct Node));
if (TmpCell == NULL)
FatalError("Out of space!!!");
else
{
TmpCell->Element = X;
TmpCell->Next = S->Next;
S->Next = TmpCell;
}
}
// 返回栈顶元素
ElementType
Top(Stack S)
{
if (!IsEmpty(S))
return S->Next->Element;
Error("Empty stack");
return 0;
}
// 弹出栈顶元素
void
Pop(Stack S)
{
PtrToNode FirstCell; // 第一个单元,即栈顶
if (IsEmpty(S))
Error("Empty stack");
else
{
FirstCell = S->Next;
S->Next = S->Next->Next;
free(FirstCell);
}
}
ElementType TopAndPop(Stack S)
{
ElementType res = Top(S);
Pop(S);
return res;
}
2.4、fatal.h
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s
", Str ), exit( 1 )
以上是关于数据结构实验四 Radix Sort And Stack的主要内容,如果未能解决你的问题,请参考以下文章