初始化
初始化函数命名:SeqListInit
解释一下为什么叫这个名字:
Seq->顺序,List->表,Init->初始化。
这些字母都是对应的单词的首字母,方便看懂。
初始化就是给一个顺序表赋值,只不过是赋值为0。这就好像你定义一个变量随手就写出(int a=0;)一样。
顺序表的本质是一个结构体,里面有多个不同的成员,这些成员分别是:a->一个数组(你也可以理解为一个指针),size->记录顺序表里有多少个元素,也叫计数,capacit->顺序表有多大空间。
我们把指针初始化成NULL,其他两个初始化成0。
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
检查容量
初始化函数命名:SeqListCheckCapacity
解释一下为什么叫这个名字:
Seq->顺序,List->表,Check->检查,Capacity->容量。
这些字母都是对应的单词的首字母,方便看懂。
这个函数的作用是:给顺序表增加数字的时候检查是否有空间放新的数字,如果没有空间,就扩容(扩大容量),让新的数字有地方插入。
void SeqListCheckCapacity(SL* ps)
59 {
60 //容量被占满或者刚开始啥也没有
61 if (ps->capacity == ps->size)
62 {
63 //如果刚开始容量是0,那么就开辟4个字节的空间
64 //如果容量不是0,那么就扩容到原来的两倍
65 int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
66 SeqListDataType* tmp = (SeqListDataType*)realloc(ps->a, newcapacity * sizeof(SeqListDataType));
67 //如果开辟失败
68 if (tmp == NULL)
69 {
70 printf("增容失败 \n");
71 exit(-1);
72 }
73 //扩容成功
74 ps->a = tmp;
75 ps->capacity = newcapacity;
76 }
77 }
头插法
头插法函数命名:SeqListPushFront
解释一下为什么叫这个名字:
Push->推,这里你可以理解成把一个数推进顺序表里,也就是插入顺序表了。Front->头,从头开始。
假设有一组数{1,2,3,4}现在要在1的前面插入0,这就是头插法。
首先我们要检查顺序表是否有足够的空间,需要调用【检查容量】函数,这个函数我在前面的已经讲过了,忘记的朋友再上去看看。
为了在头插入一个数,我们的做法是把每个数字都往后移,这样就能在最前面空出一个位置放新的数字。
那么怎么把每个数字都往后移呢?
size是最后一个数组的下标,它能记录当前顺序表有多少个数字,因为数组的下标是从0开始的,所以size-1即可得到当前顺序表的元素个数。
得到元素个数就相当于来到了数组的最后位置,这时把元素的最后位置定义成end。把这个最后位置加1,就相当于这个最后位置向后移了一位。为了把每个元素都向后移动一位,我们需要重复这个过程,并且把end减1。
每个元素都移完之后,就可以把新数字x放在空出的位置(即a【0】),增加了一个新数,顺序表的计数size也要加1。
void SeqListPushFront(SL* ps, SeqListDataType x)
15 {
16 //先检查容量是否够用
17 SeqListCheckCapacity(ps);
18 int end = ps->size - 1;
19 while (end>=0)
20 {
21 ps->a[end+1] = ps->a[end];
22 end--;
23 }
24 ps->a[0] = x;
25 ps->size++;
26
27 }
28
尾插法
尾插法函数命名:SeqListPushBack
解释一下为什么叫这个名字:
Push->推,这里你可以理解成把一个数推进顺序表里,也就是插入顺序表了。Back->尾,从尾部开始。
假设有一组数{1,2,3,4}现在要在4的后面插入5,这就是尾插法。
同样的,在顺序表里增加一个新数之前要检查是否用足够的空间,需要调用【检查容量】函数。
尾插法是最简单的插入方法,在最后增加(size处)赋值要增加的x即可。
增加之后,把计数的size加1。
void SeqListPushBack(SL* ps, SeqListDataType x)
30 {
31 //先检查容量是否够用
32 SeqListCheckCapacity(ps);
33 ps->a[ps->size] = x;
34 ps->size++;
35 }
36
头删法
头删法函数命名:SeqListPopFront
解释一下为什么叫这个名字:
Pop->删除,Front->头,从头开始。
假设有一组数{1,2,3,4}现在要把1删掉,这就是头删法。
删除之前首先要判断顺序表里是否为空,如果顺序表为空就不能删了。assert是断言函数,如果数序表的计数大于0才会执行下面的代码,否则程序终止。
为了在头删除一个数,我们的做法是把每个数字都往前移,这样就能把最前面的数字删除了。
那么怎么把每个数字都往前移呢?
我们的目的是删掉第一个数,那么就要第二个数移到第一个数的位置,也就是从第二个数开始。第二个数的下标是1,所以begin是1。
为了把所有的数都往前移,我们需要循环这个过程。每移完一个数字,都要把begin加1,直到begin来到顺序表的最后(size处)。
循环结束之后,数字也就被删除了。之后把顺序表的计数size减1。
void SeqListPopFront(SL* ps)
38 {
39 assert(ps->size > 0);
40 //为什么要begin=1?
41 //从第二个开始往前移
42 int begin = 1;
43 while (begin < ps->size)
44 {
45 ps->a[begin-1] = ps->a[begin ];
46 begin++;
47 }
48 ps->size--;
49 }
50
尾删法
尾删法函数命名:SeqListPopBack
解释一下为什么叫这个名字:
Pop->删除,back->尾,从尾部开始。
假设有一组数{1,2,3,4}现在要把4删掉,这就是尾删法。
删除之前首先要判断顺序表里是否为空,如果顺序表为空就不能删了。assert是断言函数,如果数序表的计数大于0才会执行下面的代码,否则程序终止。
尾删只需要把计数减1即可。
你可以这么理解:把最后数字【4】比做一个人,他去银行取钱,银行是叫号排队取钱,现在把他的号撕毁,永远就叫不到这个人了。
顺序表也是同理,把计数减1,就是把这个数删掉了。
void SeqListPopBack(SL* ps)
53 {
54 assert(ps->size>0);
55 ps->size--;
56 }
打印函数
尾删法函数命名:SeqListPrint
解释一下为什么叫这个名字:
Print->打印,其他的没什么好解释的了。
通过循环打印每个数字。
void SeqListPrint(SL* ps)
89 {
90 int i = 0;
91 for (i = 0; i < ps->size; i++)
92 {
93 printf("%d ", ps->a[i]);
94 }
95 printf("\n");
96 }
释放空间
因为我们的空间全部是malloc出来的,不用了要把空间还给操作系统。不然会造成空间浪费。设置可能出现内存泄露的问题。
//释放空间函数
80 void SeqListDestory(SL* ps)
81 {
82 free(ps->a);
83 ps->a = NULL;
84 ps->capacity=ps->size=0;
85
86 }
87