目录
数据结构进阶实训课程笔记和算法练习
题目1
输入数字n,按顺序打印输出从1到最大的n位十进制数。比如输入3,则打印出1,2,3,一直到最大的3位数999。
- 要考虑若n很大,我们求最大的n位数用int 或long long 也可能会溢出;
- 考虑大数问题;
- 提示:关于大数的表示和存储:用字符数组(取值为数字型字符)来表达大数
1.1 算法设计思想
这题主要解决大数问题。我用字符串来解决大数问题。
那么字符串中所有字符都是数字;
首先动态分配字符串空间为(n+1)*char,字符串最后要有一个结束符’\0’,初始化其他位为0;
然后每一次为字符串表示的数字加1,再打印出来;
方法print()会遍历字符串,直到遇到第一个非0字符后,打印后面的字符;
关键方法printRecursively(),每10个数,对具***数加1,然后进位,递归。
1.2 源代码
void printRecursively(char *number, int n, int index){
int i;
if(index == n){
print(number, n);
return;
}
for(i = 0; i<10; i++){
number[index] = i + '0';
// printf("NUMBER: %s\n", number);
printRecursively(number, n, index + 1);
}
}
void printToMaxOfNDigits(int n){
if (n <= 0)
return;
char *number = (char *)malloc((n+1)*sizeof(char));
memset(number, '0', (n+1)*sizeof(char)); // 在一段内存块中填充某个给定的值,初始化为0
number[n] = '\0';
printRecursively(number, n, 0);
free(number);
}
1.3 运行情况截图
题目2
已知一个顺序表L(整数)
实现一个函数将调整顺序表中的数字顺序,使得所有奇数位于表L的前半部分,所有偶数位于数组的后半部分。
- 如果把题目改成把顺序表中的数按照大小分为两部分,负数都在非负数的前面,该怎么做?再定义一个函数??
- 或者再改为:把顺序表中的数分为两部分,
能被3整除的数放在前面,不能被3整除的数放在后面;再定义一个函数??
- 是否有更好的办法?增加代码的可扩展性。
2.1 算法设计思想
定义一个规则rule方法,根据用户输入,确定排序规则,增加代码复用性;
三种排序规则思想一样:
(1)start=0从顺序表头开始往后,end从尾开始往前,
start遇到偶数停止,end遇到奇数停止,交换下标为start和下标为end的元素,然后继续前进;
(2)start=0从顺序表头开始往后,end从尾开始往前,
start遇到正数停止,end遇到负数停止,交换下标为start和下标为end的元素,然后继续前进;
(3)start=0从顺序表头开始往后,end从尾开始往前,
start遇到不能被3整除的数停止,end遇到能被3整除的数停止,交换下标为start和下标为end的元素,然后继续前进。
2.2 源代码
/*宏定义*/
#define MAXSIZE 30
//宏定义布尔类型
#define BOOL int
#define TRUE 1
#define FALSE 0
typedef int ElemType; /*顺序表中存放整型元素*/
typedef struct{
ElemType elem[MAXSIZE];
int last;
}SeqList;
/*函数声明*/
void initList(SeqList *L);
void printList(SeqList L);
BOOL rule(int elem, int select);
void sortList(SeqList *L, SeqList *L1, int select);
void main(){
SeqList La, Lb;
Lb.last=-1; // 初始化Lb
int select;
initList(&La);
// 给出一个顺序表La
printf("Give a sequence table: \nLa = ");
printList(La);
/* 给出下列几种排序规则: 奇数在前,偶数在后; 负数在前,非负数在后; 能被3整除的数在前面,不能被3整除的数在后面. */
printf("\nGive the following sorting rules: \ \n1.Odd number first, even number behind;\ \n2.Negative numbers first, non-negative numbers last;\ \n3.Numbers divisible by 3 are in the front, \ and numbers that are not divisible by 3 are in the back.\ \nPlease select the sorting rule you want and enter the rule number:");
scanf("%d", &select);
while(select != 1 && select != 2 && select != 3){
printf("Please reselect: ");
scanf("%d", &select);
}
sortList(&La, &Lb, select);
printf("The adjusted sequence table is: \n");
printList(Lb);
system("pause");
}
/*函数定义*/
void initList(SeqList *L){
L->last=-1;
int i=0;
for(i; i<MAXSIZE; i++){
L->elem[i]=rand()%100 - 50;
}
L->last=MAXSIZE-1;
}
void printList(SeqList L){
int i;
printf("(");
for(i=0; i<=L.last; i++)
printf("%d ", L.elem[i]);
printf(")\n");
}
void sortList(SeqList *L, SeqList *L1, int select){
int i=0, end=L->last, start=0;
for(i; i<=L->last; i++){
if( rule(L->elem[i], select) == TRUE){ // 偶数尾插法
L1->elem[end] = L->elem[i];
end--;
}
else{ // 奇数前插法
L1->elem[start] = L->elem[i];
start++;
}
}
L1->last=L->last;
}
BOOL rule(int elem, int select){
switch (select)
{
case 1:
if(elem%2==0)
return TRUE;
return FALSE;
break;
case 2:
if(elem>=0)
return TRUE;
return FALSE;
break;
case 3:
if(elem%3!=0)
return TRUE;
return FALSE;
break;
default:
return FALSE;
break;
}
}
2.3 运行情况截图
题目3
给定一个整数数组,删除相邻的重复数字,结果数组中不能存在任何相邻的重复数字。
3.1 算法设计思想
将数组存入顺序表;
遍历顺序表,将下标为i和下标i+1的元素比较如果相等,进行判断:
如果下标为i和下标i+2的元素相等,所有元素往前移动1位;
如果下标为i和下标i+2的元素不相等,所有元素往前移动2位;
持续上述循环,结束的标志是遍历顺序表,没有相邻相同元素就结束循环。
3.2 源代码
while(flag==1){
if(L.last==0) // 代表顺序表中只有一个元素
break;
if(L.elem[i]==L.elem[j]){
if(L.elem[i]==L.elem[j+1]){ // 判断是否3数相连
for(k=i; k<L.last; k++){
L.elem[k]=L.elem[k+1]; // 所有元素前移1位
}
L.last = L.last-1;
}
else{ // 不是3数相连,那就是2数相连
for(k=i; k<L.last-1; k++){
L.elem[k]=L.elem[k+2]; // 所有元素前移2位
}
L.last = L.last-2;
if(j>L.last){
i=0;
j=1;
}
}
}
if(j==L.last){
for(k=0; k<L.last; k++){
if(L.elem[k]==L.elem[k+1]){
flag=1;
break;
}
else
flag=0;
}
i=-1;
j=0;
}
i++;
j++;
}
3.3 运行情况截图
题目4
已知顺序表L(数组表示即可),编写一个时间复杂度O(n),空间复杂度为O(1)的算法
将表L中所有值为x 的元素删除。
- 表中元素无序。
4.1 算法设计思想
遍历顺序表,将顺序表a的元素赋给顺序表b,遇到要删除的元素就跳过。
4.2 源代码
void deleteList(SeqList *LA, SeqList *LB, int n){
int count=0, i=0, j=0;
for(i; i<LA->last+1; i++){
if(LA->elem[i]==n){
count++; // 记录删除元素的个数
}
else{
LB->elem[j] = LA->elem[i];
j++;
}
}
LB->last = LA->last-count;
}
4.3 运行情况截图
题目5
将n 个整数存入顺序表L,实现将L中的整数序列循环左移p(0<p<n)个位置,
即将L中的数据序列
(x0, x1, ... , xp-1, xp, xp+1, ... , xn-1)
变换为
(xp, xp+1, ... , xn-1, x0, x1, ... , xp-1)
- 类似的实现循环右移K位;
- 要求:时间复杂度为O(n)。空间复杂度为S(1)。
5.1 算法设计思想
将下标0到p的元素逆置;
将下标p+1到n 的元素逆置;
最后将整个顺序表逆置得到最终结果。
5.2 源代码
void main(){
SeqList L = {{1,2,3,4,5,6,7,8,9,10},10};
int n;
int temp;
char direction;
printf("Give a sequence table: \n");
printlist(L);
printf("Please enter a positive integer n to cycle through the sequence: ");
scanf("%d", &n);
getchar(); // 吃掉回车
printf("Please select the direction of movement (L for left, R for right): ");
while(direction!='R' && direction!='L'){
scanf("%c", &direction);
getchar();
if(direction=='L'){
n = n%L.last;
}
else if(direction=='R'){ // 右移n格就是左移L.last-n格
n = L.last - n%L.last;
}
else{
printf("Wrong input, please re-enter: ");
}
}
int i = 0, j = n-1;
//将子表(X0,X1...,Xp-1)逆序为(Xp-1,...,X1,X0)
reverse(&L, i, j);
//将子表(Xp,Xp+1,...,Xn-1)逆序为(Xn-1,...,Xp+1,Xp)
i = n;
j = L.last-1;
reverse(&L, i, j);
//将整张表(Xp-1,...,X1,X0,Xn-1,...,Xp+1,Xp)逆序为(Xp,Xp+1,...,Xn-1,X0,X1...,Xp-1)
i = 0;
j = L.last-1;
reverse(&L, i, j);
printf("The sequence table after moving is: \n");
printlist(L);
system("pause");
}
void reverse(SeqList *L,int i, int j){
int temp;
while(i < j){
temp = L->elem[i];
L->elem[i] = L->elem[j];
L->elem[j] = temp;
++i;
--j;
}
}
5.3 运行情况截图