对顺序表进行的一系列操作
头文件
#ifndef _SEQLIST_H_
#define _SEQLIST_H_
#define MAX 40 //定义顺序表的最大容量
typedef int datatype; //数据元素的类型,以整形为例
//定义顺序表类型
typedef struct
{
datatype data[MAX]; //存储数据元素的数组
int len; //存储当前顺序表的长度
}seqList, *seqListPtr; //重命名为一个结构体变量,和一个指针类型
//创建顺序表
seqListPtr list_create();
//判满
int list_full(seqListPtr S);
//判空
int list_empty(seqListPtr S);
//向顺序表中添加元素
int list_add(seqListPtr S, datatype e);
//遍历顺序表
void list_show(seqListPtr S);
//任意位置插入元素
int list_insert_pos(seqListPtr S,int pos, datatype e);
//任意位置删除元素
//按位置进行修改
//按值进行修改
//查找指定位置的元素
//按值进行查找元素
int list_search_value(seqListPtr S, datatype e);
//将顺序表排序,选择排序
void list_sort(seqListPtr S, int flag);
//顺序表去重
//扩容
//求最值操作
datatype list_mvalue(seqListPtr S, int flag);
//顺序表反转
void list_reverse(seqListPtr S);
//释放顺序表
#endif
源文件
#include"seqlist.h"
#include
#include
#include
//创建顺序表
seqListPtr list_create()
{
//在堆区申请一个顺序表的空间大小
seqListPtr S = (seqListPtr)malloc(sizeof(seqList));
//判断是否申请成功
if(NULL == S)
{
printf("顺序表创建失败\n");
return NULL;
}
//此时顺序表已经创建成功
memset(S->data, 0, sizeof(S->data)); //清空数组
S->len = 0; //数组长度清零
printf("顺序表创建成功\n");
return S;
}
//判满,成功返回真,失败返回假
int list_full(seqListPtr S)
{
//判断逻辑
if(NULL == S)
{
printf("所给顺序表不合法\n");
return 0;
}
//合法,则返回是否已经满了
return S->len == MAX;
}
//判空,如果空返回真,非空返回假
int list_empty(seqListPtr S)
{
//判断逻辑
if(NULL == S)
{
printf("所给顺序表不合法\n");
return 0;
}
//合法返回是否空
return S->len == 0;
}
//向顺序表中添加元素
int list_add(seqListPtr S, datatype e)
{
//判断逻辑
if(NULL==S || list_full(S))
{
printf("添加失败\n");
return 0;
}
//添加逻辑
S->data[S->len] = e; //将新元素放入最后一个位置
//表的变化
S->len++;
printf("添加成功\n");
return 1;
}
//遍历顺序表
void list_show(seqListPtr S)
{
//判断逻辑
if(NULL==S || list_empty(S))
{
printf("遍历失败\n");
return ;
}
//遍历逻辑
printf("当前顺序表的元素分别是:");
for(int i=0; ilen; i++)
{
printf("%d\t", S->data[i]);
}
printf("\n");
}
//任意位置插入元素
int list_insert_pos(seqListPtr S,int pos, datatype e)
{
//判断逻辑
if(NULL==S || list_full(S) || pos<0 || pos>S->len)
{
printf("插入失败\n");
return 0;
}
//腾空过程
for(int i=S->len-1; i>=pos; i--)
{
S->data[i+1] = S->data[i]; //将当前元素后移
}
//插入逻辑
S->data[pos] = e; //将新元素放入要插入的位置
//表的变化
S->len++;
printf("插入成功\n");
return 1;
}
//按值进行查找元素
int list_search_value(seqListPtr S,datatype e){
//判断逻辑
if(NULL==S || list_empty(S))
{
printf("空表无法查询\n");
return -1;
}
int flag=0; //标志是否找到值
int a; //储存找到值的位置
for(int i=0;ilen;i++){
if(S->data[i]==e){
printf("值在%d位\n",i+1); //找到后输出对应的位置
a=a*10+i+1;
flag=1;
}
}
if(flag==0){
printf("没有找到对应的值\n"); //根据标识符确定是否存在需要查找的值
return 0;
}
else if(flag==1){
return a;
}
}
//选择排序
void list_sort(seqListPtr S, int flag){
//判断逻辑
if(NULL==S || list_empty(S))
{
printf("空表无法排序\n");
return ;
}
int i,j;
int min = 0;
for(i=0;ilen-1;i++)//排序次数
{
min=i;
for(j=i+1;jlen;j++)
{
if(flag==0){
if(S->data[j]data[min])
{
min=j;//记录交换的元素下标值
}
}
else if(flag==1){
if(S->data[j]>S->data[min])
{
min=j;//记录交换的元素下标值
}
}
}
if(i != min) //交换值位置
{
datatype temp = S->data[i];
S->data[i] = S->data[min];
S->data[min] = temp;
}
}
}
//求最值
datatype list_mvalue(seqListPtr S, int flag){
int temp=S->data[0]; //让temp拿到表中第一个值
for(int i=0;ilen;i++){
if(flag==0){
if(tempdata[i]) temp=S->data[i]; //通过flag确定取最大最小值
}
else if(flag==1){
if(temp>S->data[i]) temp=S->data[i];
}
}
if(flag==0){ //输出最大/最小值
printf("最大值为:%d\n",temp);
}
else if(flag==1){
printf("最小值为:%d\n",temp);
}
}
//倒置顺序表
void list_reverse(seqListPtr S){
int head=0;
int tail=S->len-1;
datatype temp;
while(headdata[head];
S->data[head]=S->data[tail];
S->data[tail]=temp;
tail--;
head++;
}
}
测试文件
#include"seqlist.h"
int main(int argc, const char *argv[])
{
//申请一个顺序表
seqListPtr S = list_create();
//调用添加函数
list_add(S,3);
list_add(S,8);
list_add(S,2);
list_add(S,4);
//调用遍历函数
list_show(S);
//调用插入函数
list_insert_pos(S, 1, 100);
list_show(S);
//按值进行查找元素
list_search_value(S,5);
//对顺序表进行排序
list_sort(S,1);
list_show(S);
//求最值(1为最小值,0为最大值)
list_mvalue(S,1);
//顺序表反转
list_reverse(S);
list_show(S);
return 0;
}
结果
1、static在C语言中的用法
对于静态变量:
在函数内部声明的静态变量具有以下特性:
延长生命周期
可以在各个函数之间调用
只在第一次进入相关函数的时候初始化的,并且只执行一次
静态全局变量
在函数外部(全局范围)声明的静态变量具有以下特性:
生命周期与程序的执行周期相同
只作用域限于声明它们的源文件,不能被其他源文件使用
静态函数
使用'static'关键字声明的函数是静态函数。静态函数具有以下特性:
只作用域限于声明它们的源文件,不能被其他源文件调用
将函数声明为静态的,可以将其隐藏在当前源文件中,以防 止与其他源文件中具有相同名称的函数发生冲突
2、const在C语言中的用法
1. 修饰变量:
```c
const int x = 10; // 常量 x,不可修改
const float pi = 3.14159; // 常量 pi,不可修改
```
使用 `const` 关键字修饰的变量在初始化后不能被修改,任何试图修改其值的操作都将导致编译错误。
2. 修饰指针:
```c
const int* ptr; // ptr 是指向常量的指针,不能通过 ptr 修改所指向的值
int const* ptr; // 与上一行相同,ptr 是指向常量的指针
```
上述声明中的 `const` 关键字位于 `int` 关键字之前,表示指针指向的是一个常量,不能通过指针来修改该常量的值。但指针本身可以改变指向不同的常量。
```c
int* const ptr; // ptr 是一个常量指针,指向的地址不能改变
```
这里的 `const` 关键字位于指针变量名之前,表示指针本身是一个常量,一旦指针被初始化,就不能改变其指向的地址。
```c
const int* const ptr; // ptr 是一个指向常量的常量指针,既不能通过 ptr 修改所指向的值,也不能改变其指向的地址
```
3. 修饰函数参数:
```c
void printString(const char* str) {
// 函数中不能修改 str 指向的字符内容
printf("%s\n", str);
}
```
在函数声明中使用 `const` 关键字修饰指针参数,表示函数中不会修改传入指针所指向的内容。
4. 修饰函数返回值:
```c
const int getValue() {
return 42;
}
```
在函数声明中使用 `const` 关键字修饰返回值类型,表示函数返回的值不能用于修改其他变量的值。
5. 修饰结构体成员:
```c
struct Person {
const char* name;
int age;
};
```
在结构体定义中使用 `const` 关键字修饰成员变量,表示该成员在结构体中是常量,不能在结构体中修改其值。
3、结构体中字节对齐原值
1、在结构体中的每个属性会根据自己所占内存大小,来设置起始存储位置,起始存储位置必须是自身类型的整数倍
2、在上面对齐的基础上,最后整体会进行一次对齐,整体的字节个数要是一个数据的整数倍,这个数据是系统字节对齐和结构体中最大成员所占字节的之间取最小值。min(系统对齐字节数,结构体中所占内存最大的字节数)
4、数据存储的逻辑结构有哪些,什么逻辑结构
逻辑结构:表示数据元素之间的关联情况,根据元素间的关联情况,分为以下四种
1、集合结构:任意两个数据元素之间没有任何关系,只是单纯存储在同一个集合中 (例如:公交车上的每个乘客)
2、线型结构:数据元素之间存在一对一的关系,在该结构中,除了第一个元素没有前 驱,最后一个元素没有后继,其余所有数据都有且只有一个前驱和一个 后继,(例如:排队做核酸)
3、树形结构:数据元素之间存在一对多的关系。(例如:族谱、公司组织架构)
4、图形结构:数据元素之间存在多对多的关系。(例如:朋友关系)
5、数据结构的存储结构是什么,分别由哪些
存储结构:数据的逻辑结构在计算机中的映射存储
1、顺序存储:将逻辑上连续的数据元素,存储在物理内存也连续的空间内;(例如: 一根藤上七个娃)
2、链式存储:将逻辑上相邻的数据元素,存储在物理内存上随机位置;(例如:银行 柜台等待办理业务的用户)
3、索引存储:在存储数据元素时,单独创建一个索引表记录数据元素所在位置; ( 例如:课本的目录)
4、散列存储:也叫哈希存储,数据元素存储的位置跟数据元素的关键字有关。
6、宏函数与函数的区别
1、 宏函数:简单的字符串替换,不受类型限制,参数传递,编译前完成。
2、函数:参数传递,受参数类型限制,执行期间调用,支持递归,编译前完成。
3、宏体:在编译前完成的,替换字符串,可能带有副作用,调用时开销大。
4、因为函数是在执行期间调用的,所以可以进行调试;宏在编译前完成的,所以不可以进行调试。
5、函数支持递归,宏不支持。
6、函数在调用时会产生时间和空间上的开销;宏在调用时则没有,因为宏进行的只是简单的字符串替换。
7、如果使用宏比较多,宏体在展开时会产生大量的代码,大大降低运行时间。
7、宏定义与typedef的区别
1> 宏定义只是单纯的替换,不做任何正确性检测,是一个预处理指令
2> 类型重定义,需要做正确性检测,是一条语句
3> 宏替换发生在预处理阶段,而类型重定义发生在编译阶段
4> 如果是对普通单个重命名没有问题,但是对指针重命名就有问题了