初始化
#include<stdio.h> #include<malloc.h> #define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量 #define LISTINCREMENT 10 //线性表存储空间的分配增量 typedef struct{ int *elem; //存储空间基址 int length; //当前长度 int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位) }SqList; //初始化 int InitList_Sq(SqList *L) { L->elem = (int *)malloc(LIST_INIT_SIZE * sizeof(int)); //构造一个空的线性表L,分配空间 if(!L->elem) { return -1; //存储分配失败(申请失败) } L->length = 0; //空表长度为 0 L->listsize = LIST_INIT_SIZE; //初始存储容量 return 1; } int main() { SqList L; //声明一个顺序表 InitList_Sq(&L); //初始化 for(int i=0; i<10; i++) //将顺序表的前10个单元赋值为0~9, { L.elem[i] = i; L.length++; printf("%d ", L.elem[i]); } } ''' 结果: 0 1 2 3 4 5 6 7 8 9
不懂
1 ElemType
因为数据结构是讨论抽象的数据结构和算法,一种结构中元素的类型不一定是整型、字符型、浮点型或者用户自定义类型,为了不重复说明,使用过程用 “elemtype” 代表所有可能的数据类型,简单明了的概括整体。
在算法中,除特别说明外,规定ElemType的默认是int型。
2 typedef struct
typedef是类型定义的意思。typedef struct 是为了使用这个结构体方便。
具体区别在于: 若struct node{ }这样来定义结构体的话。在定义 node 的结构体变量时,需要这样写:struct node n; 若用typedef,可以这样写:typedef struct node{}NODE; 。在申请变量时就可以这样写:NODE n;其实就相当于 NODE 是node 的别名。区别就在于使用时,是否可以省去struct这个关键字。
3 InitList_Sq()是什么意思
此段函数作用:初始化线性表,并使用动态内存分配函数 malloc 为线性表分配空间
int InitList_Sq(SqList *L);//形参是个指针,只需要赋指针(地址)给它就可以了
c语言的函数参数是值调用
4 malloc()
下面是 malloc() 函数的声明。
void *malloc(size_t size)
-
size -- 内存块的大小,以字节为单位。
-
该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。
5 问题1:
-
1. L->elem = (ElemType * )malloc(LIST_INIT_SIZE*sizeof(ElemType));
2. newbase = (ElemType )realloc(L.elem,(L.listsize+LISTINCREMENT)sizeof(ElemType));
其中L是已经定义的线性表,LIST_INIT_SIZE是线性表存储空间的初始分配量,listsize是当前分配的存储容量(以sizeof(ElemType)为单位)
解释:
第一个句子: 用malloc分配一段这么 LIST_INIT_SIZE * sizeof(ElemType) 多个字节的内存段,它返回一个指向该内存段首字节的指针变量,然后把这个指针变量强制转换为ElemType*类型,再把这个经转换的指针变量赋给L的elem成员 第二个句子: 先看一段话:
6 realloc语法:
指针名=(数据类型 * )realloc(要改变内存大小的指针名,新的大小)。 新的大小一定要大于原来的大小,不然的话会导致数据丢失! 所以你这个句子的意思是:把L的elem指向的那段内存扩大LISTINCREMENT*sizeof(ElemType)个字节。
6 sizeof的用法:
这是一个运算符(而不是一个函数,这点认识很重要)
sizeof(类型说明符,数组名或表达式) 或 sizeof 变量名 得到一个对象或者类型所占的内存字节数。 例如,如果你的机器上int占4字节,那么sizeof(int)就是4
malloc用法:
它是一个函数,原型是void *malloc(size_t size); 前面提过了,就是分配size个字节的内存,然后返回指向这段内存首字节的指针,void * 表示未确定类型的指针,void *可以指向任何类型的数据,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者...),所以你要用它指向什么数据,一般就要在malloc前加一个强制转换,把这个指针转为适合你使用的类型。
7 L->elem = (int *)malloc(LIST_INIT_SIZE * sizeof(int));
分配一个存储容量的大小LIST_INIT_SIZE×sizeof(ElemType)的存储空间.L->elem指向这存储空间的首地址.这是线性表的内容吧.打个比方说:就是建造了一个数组,比如说啊a[10],但这个数组是空的,L->elem就是指向数组的首地址.
8 顺序表的插入
要在第 i (1<=i<=n)个元素之前插入元素,共n-i+1个元素依次向后移一个位置。
插入下标位置 i | 0 | 1 | 2 | ··· | i | ··· | n-1 | n |
---|---|---|---|---|---|---|---|---|
移动次数 | n | n-1 | n-1 | ··· | n-i | ··· | 1 | 0 |
若长度为n的线性表采用顺序存储结构,在其第 i 个位置插入一个新元素的算法时间复杂度为O(n)
若i = n,算法时间复杂度为O(1)
#include<stdio.h> #include<malloc.h> #define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量 #define LISTINCREMENT 10 //线性表存储空间的分配增量 typedef struct{ int *elem; //存储空间基址 int length; //当前长度 int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位) }SqList; int InitList_Sq(SqList *L) { L->elem = (int *)malloc(LIST_INIT_SIZE * sizeof(int)); //构造一个空的线性表L if(!L->elem) { return -1; //存储分配失败(申请失败) } L->length = 0; //空表长度为 0 L->listsize = LIST_INIT_SIZE; //初始存储容量 return 1; } //插入(老师版本) int ListInsert_Sq(SqList *L, int i, int e) //在顺序表的第i个位置插入元素e { int k; //i的范围区间[1, ListLength_Sq(L)+1] if(i<1 || i>L->length+1) { return -1; //i的值不合法 } if(L->length >= L->listsize) //存储空间=分配空间,空间已满,增加分配 { L->elem= (int *)realloc(L->elem, (L->listsize+LISTINCREMENT) * sizeof(int)); if(!L->elem) { return -1; //存储分配失败 } L->listsize += LISTINCREMENT; //增加存储容量 } for (k=L->length; k>i-1; k--) { L->elem[k]=L->elem[k-1]; } L->elem[k]=e; //插入元素e L->length++; //顺序表长度加1 return 1; } /*插入(用指针) int ListInsert_Sq(SqList *L, int i, int e) //在顺序表的第i个位置插入元素e { //i的范围区间[1, ListLength_Sq(L)+1] if(i<1 || i>L->length+1) { return -1; //i的值不合法 } if(L->length >= L->listsize) //存储空间=分配空间,空间已满,增加分配 { int *newbase = (int *)realloc(L->elem, (L->listsize+LISTINCREMENT) * sizeof(int)); if(!newbase) { return -1; //存储分配失败 } L->elem = newbase; //新基址 L->listsize += LISTINCREMENT; //增加存储容量 } int *q = &(L->elem[i-1]); //q为插入的位置 for (int *p=&(L->elem[L->length-1]); p>=q; --p) //p为最后一个位置,用来移动元素 { *(p+1) = *p; //插入位置及之后的元素右移 } *q = e; //插入元素e ++L->length; //表长增1 return 1; } */ int main() { SqList L; //声明一个顺序表 InitList_Sq(&L); //初始化 for(int i=1; i<=10; i++) //空表中,逐个插入1~10 { ListInsert_Sq(&L, i, i); } for(int i=0; i<10; i++) //遍历、打印 { printf("%d ", L.elem[i]); } } ''' 结果: 1 2 3 4 5 6 7 8 9 10
9 删除
删除下标位置 i | 0 | 1 | 2 | ··· | i | ··· | n-2 | n-1 |
---|---|---|---|---|---|---|---|---|
移动次数 | n-1 | n-2 | n-3 | ··· | n-i+1 | ··· | 1 | 0 |
若长度为n的线性表采用顺序存储结构,在其第 i 个位置删除一个元素的算法时间复杂度为O(n)
若i = n-1,算法时间复杂度为O(1)
#include<stdio.h> #include<malloc.h> #define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量 #define LISTINCREMENT 10 //线性表存储空间的分配增量 typedef struct{ int *elem; //存储空间基址 int length; //当前长度 int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位) }SqList; int InitList_Sq(SqList *L) { L->elem = (int *)malloc(LIST_INIT_SIZE * sizeof(int)); //构造一个空的线性表L if(!L->elem) { return -1; //存储分配失败(申请失败) } L->length = 0; //空表长度为 0 L->listsize = LIST_INIT_SIZE; //初始存储容量 return 1; } int ListDelete_Sq(SqList *L, int i, int *e) //在顺序表L中删除第i个元素,用e返回其值 { //i的范围区间[1, ListLength_Sq(L)+1] if(i<1 || i>L->length) { return -1; //i值不合法 } int *p = &(L->elem[i-1]); //指针p指向被删除元素的位置 *e = *p; //被删除的元素赋值给e int *q = &(L->elem[L->length-1]); //指针p指向表尾元素的位置 for(++p; p<=q; ++p) { *(p-1) = *p; //被删除元素之后的元素左移 } --L->length; //表长减1 return 1; } int main() { SqList L; //声明一个顺序表 InitList_Sq(&L); //初始化 for(int i=0; i<10; i++) { L.elem[i] = i; //空表中,逐个赋值0~9 printf("%d ", L.elem[i]); L.length++; } printf("\n"); int e = 0; ListDelete_Sq(&L, 6, &e); printf("被删除的元素是:%d\n", e); printf("删除后的顺序表:"); for(int i=0; i<9; i++) { printf("%d ", L.elem[i]); } }