网上关于数据结构c语言的代码稂莠不齐,有时候查找作业容易被不好的代码代入沟里,于是写了这个系列来提供一些参考,如果有什么错误也请大佬指正。
以下所有的程序都是经过多次修改的,函数编写方面不单单看重结果,有时候结果对,函数本身也是不规范的或是错误的
第一题.删除顺序表中大于x的元素。例如,线性表L=(3,7,1,5,9,6,4),x=5,执行算法后L变为(3,1,5,4).
思路:直接在原表上进行覆盖,节省空间
算法函数如下:只传入线性表和x,函数设计中不应传入其他无关紧要的参数,比如有些人会传入j,或者在写低效算法时,会传入另外一个线性表作为存储空间,都是不规范的,调用者使用函数时,只需要传入线性表和x即可,就跟sin()函数一样,调用者在使用时,只用传入x,而不是传入跟计算无关的值.如果那么做了,就会显得很奇怪,比如计算sin,要写一个sin(x,y,z),才能计算出来sin(x),y和z是编写函数的人自定义的,但是函数调用者并不知道,这种编写方式是错误的
下面看算法代码
//删除顺序表中大于x的元素
void ListDelete(SqList *L,int x){
int j=0;//记录位置
for(int i=0;i<(*L).length;i++){
if((*L).elem[i]<=x){
(*L).elem[j]=(*L).elem[i];
j++;
}
}
(*L).length = j;
}
调用(*L).elem动态数组,并且用j记录位置,以题目为例,循环遍历从3开始,小于x=5,将赋值到(*L).elem[j],初始j=0,就是赋值到第一个位置,j++,如果大于x,不作变动,只将小于x的值覆盖到前面
第一次循环:(3,7,1,5,9,6,4) x=5 (3<=5,3赋值到前面) j=1:指向第二个数
第二次循环:(3,7,1,5,9,6,4) x=5 j=1:指向第二个数
第三次循环:(3,1,1,5,9,6,4) x=5 (1<=5,1赋值到前面) j=2:指向第三个数
第四次循环:(3,1,5,5,9,6,4) x=5 (5<=5,5赋值到前面) j=3:指向第四个数
第五次循环:(3,1,5,5,9,6,4) x=5
第六次循环:(3,1,5,5,9,6,4) x=5
第七次循环:(3,1,5,4,9,6,4) x=5 (4<5,4赋值到j的位置)
循环结束,(*L).length忠实的记录顺序表的长度,此时为4(实际上不为4,因为后面的空间未删除,但是当你设定它为4的时候,以后的操作都相当于长度为4了)
完整代码如下
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
const int ListInitSize = 100; //线性表初始存储空间
const int ListInc = 10; //线性表存储空间的分配增量
typedef struct{
int *elem; //存储线性表元素的动态数组
int length,listsize; //表的长度与当前分配的存储容量
} SqList;
//顺序表初始化操作,存入若干数据
bool ListInit(SqList *L,int n,int a[]);
//删除顺序表中大于x的元素
void ListDelete(SqList *L,int x);
int main(){
SqList L;
int n=7,a[7]={3,7,1,5,9,6,4},x=5;
ListInit(&L,n,a);
ListDelete(&L,x);
printf("线性表L =(");
for(int i=0;i<L.length;i++){
printf("%d ",L.elem[i]);
}
printf(")");
}
//顺序表初始化操作,存入若干元素
bool ListInit(SqList *L,int n,int a[]){
(*L).elem =(int*)malloc((ListInitSize+n)*sizeof(int));//分配内存
if(!(*L).elem){//分配内存失败
return false;
}
(*L).length = n;
(*L).listsize = n+ListInitSize;
for(int i=0;i<n;i++){
(*L).elem[i]=a[i];
}
}
//删除顺序表中大于x的元素
void ListDelete(SqList *L,int x){
int j=0;
for(int i=0;i<(*L).length;i++){
if((*L).elem[i]<=x){
(*L).elem[j]=(*L).elem[i];
j++;
}
}
(*L).length = j;
}
第二题.改变顺序表的元素次序,第奇数个元素移到前面,第偶数个元素移到后面.例,线性表L=(1,2,3,4,5,6,7)变为(1,3,5,7,2,4,6).
思路:对原有顺序表的排序,并存储到新的动态数组上,最后将数组整个赋值给原有顺序表,这样的时间复杂度只有一重循环了,如果考虑节省空间,也可以将原有动态数组删除.
动态数组的赋值实际上是将地址传过去了,不需要再开一个循环去赋值
算法代码如下:缺点如下:n的取整不用这么麻烦,有更简单的,而且受惯性思维影响,写代码时人为分了奇偶,不用分奇偶两种情况也可以赋值,读者可以自行思考
//奇数项移到前面,偶数项移到后面
bool ListMove(SqList *L){
int *A;//一个新的动态数组
A =(int*)malloc(((*L).listsize)*sizeof(int));//动态数组分配内存
if(!A){//分配内存失败
return false;
}
int n=(int)ceil(((double)(*L).length)/2);//除以2并向上取整
if((*L).length%2==0){//判断如果顺序表有偶数个元素
for(int i=0;i<n;i++){
A[i+n]=(*L).elem[2*i+1];//偶数项插入
A[i]=(*L).elem[2*i];//奇数项插入
}
}
else{//判断如果顺序表有奇数数个元素
A[0]=(*L).elem[0];
for(int i=1;i<n;i++){
A[i+n-1]=(*L).elem[2*i-1];//偶数项插入
A[i]=(*L).elem[2*i];//奇数项插入
}
}
(*L).elem = A;//直接赋值地址
return true;
}
完整代码如下
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <math.h>
const int ListInitSize = 100; //线性表初始存储空间
const int ListInc = 10; //线性表存储空间的分配增量
typedef struct{
int *elem; //存储线性表元素的动态数组
int length,listsize; //表的长度与当前分配的存储容量
} SqList;
//顺序表初始化操作,存入若干数据
bool ListInit(SqList *L,int n,int a[]);
//奇数项移到前面,偶数项移到后面
bool ListMove(SqList *L);
int main(){
SqList L;
int n=21,a[21]={1,2,3,4,5,6,7,8,10,12,14,16,18,20,23,26,29,33,37,41,44};
ListInit(&L,n,a);
ListMove(&L);
printf("线性表L =(");
for(int i=0;i<L.length;i++){
printf("%d ",L.elem[i]);
}
printf(")");
}
//顺序表初始化操作,存入若干元素
bool ListInit(SqList *L,int n,int a[]){
(*L).elem =(int*)malloc((ListInitSize+n)*sizeof(int));//分配内存
if(!(*L).elem){//分配内存失败
return false;
}
(*L).length = n;
(*L).listsize = n+ListInitSize;
for(int i=0;i<n;i++){
(*L).elem[i]=a[i];
}
return true;
}
//奇数项移到前面,偶数项移到后面
bool ListMove(SqList *L){
int *A;
A =(int*)malloc(((*L).listsize)*sizeof(int));//动态数组分配内存
if(!A){//分配内存失败
return false;
}
int n=(int)ceil(((double)(*L).length)/2);//除以2并向上取整
if((*L).length%2==0){
for(int i=0;i<n;i++){
A[i+n]=(*L).elem[2*i+1];//偶数项插入
A[i]=(*L).elem[2*i];//奇数项插入
}
}
else{
A[0]=(*L).elem[0];
for(int i=1;i<n;i++){
A[i+n-1]=(*L).elem[2*i-1];//偶数项插入
A[i]=(*L).elem[2*i];//奇数项插入
}
}
(*L).elem = A;
return true;
}
持续更新中......