1.1 顺序表C
<h1>1.1 顺序表的构建</h1>
<pre><code class="language-c">#include&lt;stdio.h&gt; // 包含标准输入输出库,用于进行输入输出操作。
#include&lt;stdlib.h&gt; // 包含标准库,用于使用动态内存分配和其它标准函数。
// 定义一个类型别名 EType,这里指定为 int 类型。
typedef int EType;
// 定义一个结构体 Seq,用于表示顺序存储的集合。
typedef struct Seq{
int size; // 表示集合的最大容量。
int curNum; // 表示当前集合中元素的数量。
EType* element; // 指向一个动态分配的数组,用于存储集合中的元素。
}Seq;
// 注意:这段代码只是定义了两个类型(EType 和 Seq),并没有实现任何函数或主程序逻辑。</code></pre>
<p>其中EType是顺序表中的元素的类型,上课使用的是int,但是要注意:它可以是任意类型。</p>
<h1>1.2 顺序表的操作</h1>
<h2>辅助操作</h2>
<h3>【初始化/创建】</h3>
<pre><code class="language-c">Seq* init(int size) {
// 检查传入的size是否合法,如果小于等于0,则返回NULL,表示初始化失败
if(size &lt;= 0) {
return NULL;
}
// 动态分配内存空间给Seq结构体,并将其地址赋值给seq指针
Seq* seq = (Seq*)malloc(sizeof(Seq));
// 检查动态分配是否成功,如果失败则返回NULL
if(seq == NULL) {
return NULL;
}
// 初始化当前元素数量为0
seq-&gt;curNum = 0;
// 设置集合的最大容量
seq-&gt;size = size;
// 为元素数组分配内存空间,大小为size*sizeof(EType),这里size是集合的最大容量
seq-&gt;element = (EType*)malloc(size*sizeof(EType));
// 检查元素数组的内存分配是否成功,如果失败则释放之前分配的Seq结构体内存,并返回NULL
if(seq-&gt;element == NULL) {
free(seq);
return NULL;
}
// 如果所有内存分配都成功,则返回Seq结构体的指针
return seq;
}</code></pre>
<p>这个init函数的目的是初始化一个Seq结构体,为它分配内存,并设置初始状态。它首先检查传入的size是否合法,然后为Seq结构体和它的element数组分配内存。如果在任何时候内存分配失败,函数会释放已分配的内存并返回NULL。如果一切顺利,函数返回指向新初始化的Seq结构体的指针。</p>
<h3>【销毁】</h3>
<pre><code class="language-c">void destory(Seq* s) {
// 释放Seq结构体中元素数组所占用的内存
free(s-&gt;element);
// 释放Seq结构体自身所占用的内存
free(s);
}</code></pre>
<p>这个destory函数的目的是对之前使用init函数创建的Seq结构体进行清理,释放其占用的内存。这里需要注意的是,函数名destory可能是一个拼写错误,通常正确的拼写应该是destroy。</p>
<p>函数接受一个指向Seq结构体的指针s作为参数,然后依次释放该结构体的element数组和结构体本身所占用的内存。在调用这个函数后,原来的Seq结构体和其元素数组将不再有效,因此不应再访问这些内存区域。</p>
<h3>【格式化输出】</h3>
<pre><code class="language-c">void show(Seq* s) {
// 定义一个整型变量i,用于在循环中作为索引
int i;
// 使用for循环遍历Seq结构体中的元素数组
// 循环条件是i小于s-&gt;curNum,即当前元素数量
for(i = 0; i &lt; s-&gt;curNum; i++) {
// 打印出当前索引i处的元素值
printf(&quot;%d &quot;, s-&gt;element[i]);
}
// 在循环结束后打印一个换行符,以美观地分隔输出结果
printf(&quot;\n&quot;);
}</code></pre>
<p>这个show函数的目的是打印出Seq结构体中当前存储的所有元素。它接受一个指向Seq结构体的指针s作为参数,然后使用一个for循环遍历这个结构体的element数组,直到curNum指示的当前元素数量。在每次迭代中,函数使用printf函数打印出数组中的一个元素。循环结束后,函数打印一个换行符,以便在命令行或控制台上美观地分隔输出结果。</p>
<h3>【扩容】</h3>
<p>当超出容量时,可以报错,也可以选择扩容:</p>
<pre><code class="language-c">int grow(Seq* s, int k) {
// 检查k是否小于等于0,如果是,则返回1表示失败
if(k &lt;= 0){
return 1;
}
// 将Seq结构体的size成员乘以k,从而扩大容量
s-&gt;size *= k;
// 动态分配新的内存空间,大小为s-&gt;size * sizeof(EType),用于存储更多的元素
EType* e = (EType*)malloc((s-&gt;size)*sizeof(EType));
// 检查新分配的内存是否为空,如果为空,则返回1表示失败
if(e == NULL){
return 1;
}
int i;
// 使用for循环将旧元素数组的内容复制到新的元素数组
for(i = 0; i &lt; s-&gt;curNum; i++){
e[i] = s-&gt;element[i];
}
// 释放旧的元素数组占用的内存
free(s-&gt;element);
// 将Seq结构体的element成员指向新的元素数组
s-&gt;element = e;
// 返回0表示成功
return 0;
}</code></pre>
<p>这个grow函数的目的是扩展Seq结构体的容量。它接受一个指向Seq结构体的指针s和一个扩展因子k作为参数。函数首先检查k是否有效,然后将结构体的容量扩大k倍,并分配新的内存空间来存储更多的元素。接着,函数将旧数组中的元素复制到新的数组中,释放旧数组的内存,并将结构体的element成员指向新的数组。如果任何时候出现错误(例如,内存分配失败),函数将返回1表示失败。如果所有操作都成功完成,函数将返回0。</p>
<h3>【判断是不是空】</h3>
<pre><code class="language-c">int isempty(Seq* s){
// 检查传入的Seq结构体指针s是否为空
// 如果Seq结构体的curNum成员等于0,即没有元素,则返回1(真),表示集合为空
// 否则返回0(假),表示集合不为空
return s-&gt;curNum == 0;
}</code></pre>
<p>这个isempty函数的目的是检查传入的Seq结构体是否为空。它通过检查Seq结构体的curNum成员是否为0来判断集合是否为空。如果curNum为0,表示集合中没有任何元素,函数返回1(在C语言中通常用1表示真,0表示假)。如果curNum不为0,表示集合中有元素,函数返回0。这是一种常见的习惯用法,用以表示布尔值真和假。</p>
<h3>【判断是不是满】</h3>
<pre><code class="language-c">int isfull(Seq* s){
// 检查传入的Seq结构体指针s是否指向一个有效的Seq结构体
// 返回s-&gt;curNum == s-&gt;size的结果,即检查当前元素数量是否等于最大容量
// 如果相等,返回1表示集合已满,否则返回0表示集合未满
return s-&gt;curNum == s-&gt;size;
}</code></pre>
<p>这个isfull函数的目的是检查传入的Seq结构体是否已满。它通过比较Seq结构体的curNum成员(当前元素数量)和size成员(最大容量)来判断集合是否已满。如果两者相等,表示集合中已经没有更多空间可以添加新元素,函数返回1(在C语言中通常用1表示真,0表示假)。如果两者不相等,表示集合中还有空间,函数返回0。这样的设计允许调用者根据返回值判断集合是否需要扩容。</p>
<h2>增加元素</h2>
<h3>【添加】</h3>
<p>方式1:当容量满了,扩容</p>
<pre><code class="language-c">void append1(Seq* s, int m) {
// 检查传入的Seq结构体s是否已满
if(isfull(s)){
// 如果已满,调用grow函数将Seq结构体的容量扩大两倍
grow(s, 2);
}
// 将传入的值m追加到Seq结构体的元素数组的当前位置
s-&gt;element[s-&gt;curNum] = m;
// 更新Seq结构体的当前元素数量
s-&gt;curNum += 1;
}</code></pre>
<p>这个append1函数的目的是向Seq结构体追加一个新元素。它接受一个指向Seq结构体的指针s和一个要追加的值m作为参数。函数首先检查Seq结构体是否已满,如果是,则调用grow函数来扩大容量。然后,函数将新元素m存储在Seq结构体的element数组的curNum索引处,并增加curNum的值以反映新添加的元素。</p>
<p>方式2:当容量满了,不执行,方法返回1,表示操作失败,否则返回0</p>
<pre><code class="language-c">int append2(Seq* s, int m) {
// 检查传入的Seq结构体s是否已满
if(isfull(s)){
// 如果已满,返回1表示操作失败
return 1;
}
// 将传入的值m追加到Seq结构体的元素数组的当前位置
s-&gt;element[s-&gt;curNum] = m;
// 更新Seq结构体的当前元素数量
s-&gt;curNum += 1;
// 返回0表示操作成功
return 0;
}</code></pre>
<p>这个append2函数的目的是向Seq结构体追加一个新元素,并返回操作的结果。它接受一个指向Seq结构体的指针s和一个要追加的值m作为参数。函数首先检查Seq结构体是否已满,如果是,则返回1表示操作失败。如果未满,函数将新元素m存储在Seq结构体的element数组的curNum索引处,并增加curNum的值以反映新添加的元素。最后,函数返回0表示操作成功。</p>
<p>这种设计方式使得调用者可以根据返回值判断操作是否成功,提供了更明确的反馈。与append1函数相比,append2函数在数组满时不进行扩容,而是直接返回失败状态。</p>
<h3>【插入】</h3>
<p>方式1:当容量满了,扩容</p>
<pre><code class="language-c">int insert1(Seq* s, int i, int m) {
// 检查插入位置i是否在有效范围内,如果不在则返回1表示失败
if(i &lt; 0 || i &gt; s-&gt;curNum) {
return 1;
}
// 检查Seq结构体是否已满,如果已满则打印信息并扩大容量
if(isfull(s)) {
printf(&quot;满了&quot;);
grow(s, 2); // 将容量扩大两倍
}
int j;
// 从当前最后一个元素开始,向后移动元素,为新元素腾出空间
for(j = s-&gt;curNum; j &gt; i; j--) {
s-&gt;element[j] = s-&gt;element[j-1];
}
// 在位置i插入新元素m
s-&gt;element[i] = m;
// 更新Seq结构体的当前元素数量
s-&gt;curNum += 1;
// 返回0表示插入操作成功
return 0;
}</code></pre>
<p>这个insert1函数的目的是在一个指定的位置i插入一个新的元素m。它接受一个指向Seq结构体的指针s、一个插入位置i和要插入的值m作为参数。函数首先检查插入位置是否有效,如果无效则返回1表示失败。然后检查Seq结构体是否已满,如果已满则调用grow函数扩大容量。接下来,函数通过一个循环将从插入位置i开始的元素向后移动,为新元素腾出空间。在位置i插入新元素m后,更新Seq结构体的curNum以反映新添加的元素数量。最后,函数返回0表示插入操作成功。</p>
<p>方式2:当容量满了,不执行,方法返回1,表示操作失败,否则返回0</p>
<pre><code class="language-c">int insert2(Seq* s, int i, int m) {
// 检查插入位置i是否在有效范围内,如果不在则返回1表示失败
if(i &lt; 0 || i &gt; s-&gt;curNum) {
return 1;
}
// 检查Seq结构体是否已满,如果已满则打印信息并返回1表示失败
if(isfull(s)) {
printf(&quot;满了&quot;);
return 1;
}
// 定义一个整型变量j,用于在循环中作为索引
int j;
// 从当前最后一个元素开始,向后移动元素,为新元素腾出空间
// 循环直到达到要插入新元素的位置i
for(j = s-&gt;curNum; j &gt; i; j--) {
s-&gt;element[j] = s-&gt;element[j-1];
}
// 在位置i插入新元素m
s-&gt;element[i] = m;
// 更新Seq结构体的当前元素数量
s-&gt;curNum += 1;
// 返回0表示插入操作成功
return 0;
}</code></pre>
<p>这个insert2函数的目的是在一个指定的位置i插入一个新的元素m。它接受一个指向Seq结构体的指针s、一个插入位置i和要插入的值m作为参数。函数首先检查插入位置是否有效,如果无效则返回1表示失败。然后检查Seq结构体是否已满,如果已满则打印“满了”信息并返回1表示失败。接下来,函数通过一个循环将从插入位置i开始的元素向后移动,为新元素腾出空间。在位置i插入新元素m后,更新Seq结构体的curNum以反映新添加的元素数量。最后,函数返回0表示插入操作成功。</p>
<p>与insert1函数相比,insert2函数在数组满时不进行扩容,而是直接返回失败状态。此外,insert2函数中没有扩容的代码,因此在数组满时无法插入新元素。</p>
<h3>【拼接】</h3>
<p>其中append在前文已经实现:</p>
<p>方式1:拼接时,通过grow方式增加容量</p>
<pre><code class="language-c">void extend1(Seq* s1, Seq* s2) {
// 循环检查s1是否有足够的空间来扩展以包含s2中的所有元素
while(s1-&gt;curNum + s2-&gt;curNum &gt; s1-&gt;size) {
// 如果空间不足,将s1的容量扩大两倍
grow(s1, 2);
}
// 定义一个整型变量i,用于在循环中作为索引
int i;
// 遍历s2中的所有元素
for(i = 0; i &lt; s2-&gt;curNum; i++) {
// 将s2中的每个元素追加到s1的末尾
append1(s1, s2-&gt;element[i]);
}
}</code></pre>
<p>这个extend1函数的目的是将两个序列s1和s2合并,即将s2中的所有元素追加到s1的末尾。函数接受两个指向Seq结构体的指针s1和s2作为参数。</p>
<p>在合并前,函数通过一个while循环检查s1是否有足够的空间来容纳s2中的所有元素。如果s1的当前容量不足以包含两个序列的元素总数,就通过调用grow函数将s1的容量扩大两倍。一旦s1有足够的空间,函数使用一个for循环遍历s2中的每个元素,并将这些元素逐一追加到s1的末尾。这里调用了append1函数来追加每个元素,该函数在必要时会扩展s1的容量。</p>
<p>请注意,grow函数的第二个参数应该是2,表示将容量扩大两倍,以确保有足够的空间来合并两个序列。如果传递的参数不正确,可能会导致无法正确扩展容量。</p>
<p>方式2:拼接时,直接合并两者容量:</p>
<pre><code class="language-c">int extend2(Seq* s1, Seq* s2){
// 将s1的容量增加s2的容量,以便有足够的空间来存放s2中的所有元素
s1-&gt;size += s2-&gt;size;
// 为新的容量分配内存空间
EType* e = (EType*)malloc((s1-&gt;size)*sizeof(EType));
// 检查内存分配是否成功,如果失败则返回1表示操作失败
if(e == NULL){
return 1;
}
int i;
// 将s1中原有的元素复制到新分配的内存空间
for(i = 0; i &lt; s1-&gt;curNum; i++){
e[i] = s1-&gt;element[i];
}
// 释放s1原来元素数组占用的内存空间
free(s1-&gt;element);
// 将s1的element指针指向新分配的内存空间
s1-&gt;element = e;
// 遍历s2中的所有元素,并将它们追加到s1中
for(i = 0; i &lt; s2-&gt;curNum; i++){
append1(s1, s2-&gt;element[i]);
}
// 释放s2中元素数组占用的内存空间
free(s2-&gt;element);
// 操作成功,返回0
return 0;
}</code></pre>
<p>这个extend2函数的目的是将两个序列s1和s2合并,即将s2中的所有元素追加到s1的末尾。函数接受两个指向Seq结构体的指针s1和s2作为参数。</p>
<p>函数首先计算新的总容量,然后分配足够的内存空间来存放两个序列的所有元素。接着,函数复制s1中原有的元素到新分配的内存空间,释放s1原来的内存空间,并将s1的element指针指向新的内存空间。</p>
<p>然后,函数遍历s2中的每个元素,并将它们逐一追加到s1的末尾。这里调用了append1函数来追加每个元素。最后,函数释放s2原来的内存空间,并返回0表示操作成功。</p>
<p>请注意,这个函数在合并两个序列时,会释放s2的内存空间,这意味着在函数执行完毕后,s2将不再有效。如果需要保留s2的数据,应该避免使用这种方法。此外,这种方法在合并大量数据时可能效率较低,因为它需要分配和复制大量内存空间。</p>
<h2>删除元素</h2>
<h3>【弹出一个元素】</h3>
<pre><code class="language-c">int pop(Seq* s) {
// 检查传入的Seq结构体s是否为空
if(isempty(s)){
// 如果Seq结构体为空,则返回1表示操作失败
return 1;
}
// 将Seq结构体的当前元素数量curNum减1,实现弹出最后一个元素的效果
s-&gt;curNum -= 1;
// 返回0表示弹出操作成功
return 0;
}</code></pre>
<p>这个pop函数的目的是从一个Seq结构体中弹出最后一个元素。它接受一个指向Seq结构体的指针s作为参数。函数首先检查Seq结构体是否为空,如果是空的则返回1表示操作失败。如果结构体不为空,函数将Seq结构体的curNum成员减1,从而减少当前元素数量,实现弹出最后一个元素的效果。最后,函数返回0表示弹出操作成功。</p>
<p>请注意,这个函数实际上并没有真正从数组中移除元素,只是减少了curNum的值。如果需要真正地移除元素并释放内存,可能需要编写额外的代码来处理数组元素的移动和内存释放。此外,由于没有返回被弹出元素的值,调用者无法知道弹出的是哪个元素。如果需要获取弹出元素的值,函数的设计可能需要进行相应的修改。</p>
<h3>【删除第i个】</h3>
<pre><code class="language-c">int popi(Seq* s, int i) {
// 检查传入的Seq结构体s是否为空
if(isempty(s)){
// 如果Seq结构体为空,则返回1表示操作失败
return 1;
}
// 检查索引i是否在有效范围内
if(i &lt; 0 || i &gt;= s-&gt;curNum){
// 如果索引i无效,则返回1表示操作失败
return 1;
}
// 定义一个整型变量j,用于在循环中作为索引
int j;
// 从索引i开始,将索引i之后的元素向前移动一位,覆盖索引i处的元素
for(j = i; j &lt; s-&gt;curNum - 1; j++){
s-&gt;element[j] = s-&gt;element[j + 1];
}
// 将Seq结构体的当前元素数量curNum减1,实现弹出索引i处元素的效果
s-&gt;curNum -= 1;
// 返回0表示弹出操作成功
return 0;
}</code></pre>
<p>这个popi函数的目的是从一个Seq结构体中弹出指定位置i的元素。它接受一个指向Seq结构体的指针s和一个要弹出的元素索引i作为参数。函数首先检查Seq结构体是否为空,如果是空的则返回1表示操作失败。然后检查索引i是否有效,如果索引无效则返回1表示操作失败。</p>
<p>如果索引有效,函数通过一个for循环将从索引i开始的元素向前移动一位,从而覆盖索引i处的元素。循环直到s->curNum - 1,确保不会越界。接着,函数将Seq结构体的curNum成员减1,减少当前元素数量,实现弹出索引i处元素的效果。最后,函数返回0表示弹出操作成功。</p>
<p>请注意,这个函数实际上移动了数组中的元素,而没有释放任何内存。如果Seq结构体中存储的是动态分配的内存或其他资源,可能需要额外的逻辑来适当地释放这些资源。此外,由于没有返回被弹出元素的值,调用者无法知道弹出的是哪个元素。如果需要获取弹出元素的值,函数的设计可能需要进行相应的修改。</p>
<h3>【删除n这个值】</h3>
<pre><code class="language-c">void remove_(Seq* s, int n) {
// 定义一个整型变量j,用于在循环中作为索引
int j;
// 从Seq结构体的最后一个元素开始向前遍历
for(j = s-&gt;curNum - 1; j &gt;= 0; j--) {
// 检查当前元素是否等于要删除的元素n
if(s-&gt;element[j] == n) {
// 如果找到匹配的元素,则调用popi函数删除该元素
popi(s, j);
}
}
}</code></pre>
<p>这个remove_函数的目的是从一个Seq结构体中删除所有等于给定值n的元素。它接受一个指向Seq结构体的指针s和一个要删除的元素值n作为参数。</p>
<p>函数通过一个for循环从Seq结构体的最后一个元素开始向前遍历。这样做是为了避免在删除元素时影响到未遍历的元素的索引。循环中,函数检查当前遍历到的元素是否等于要删除的元素n。如果找到匹配的元素,函数调用popi函数删除该元素。popi函数会负责更新Seq结构体的curNum和元素数组。</p>
<p>请注意,这个函数在找到第一个匹配的元素后不会立即停止,而是继续遍历直到数组的开始,以确保删除所有匹配的元素。此外,由于popi函数会更新数组,因此在调用popi时要特别小心,避免在遍历过程中改变数组的索引。</p>
<h3>【清空】</h3>
<pre><code class="language-c">void clear(Seq* s) {
// 将Seq结构体的当前元素数量curNum设置为0
s-&gt;curNum = 0;
}</code></pre>
<p>这个clear函数的目的是清空一个Seq结构体中的所有元素。它接受一个指向Seq结构体的指针s作为参数。函数通过将Seq结构体的curNum成员设置为0,实际上是将当前元素数量重置为零,从而实现了清空集合的效果。</p>
<h3>【删除一段】</h3>
<pre><code class="language-c">void cut(Seq* s, int start, int end) {
// 定义一个整型变量i,用于在循环中作为索引
int i;
// 从end-1开始向下遍历到start(包含start),这表示我们要删除从start到end之间的所有元素
for(i = end - 1; i &gt;= start; i--) {
// 对于每个索引i,调用popi(s, i)来删除当前索引处的元素
// popi函数会调整Seq结构体中的元素数量和数组内容
popi(s, i);
}
}</code></pre>
<p>这个cut函数的目的是从一个Seq结构体中删除从索引start到end(包含end)的所有元素。它接受一个指向Seq结构体的指针s,以及两个整数start和end作为参数,分别表示要删除元素的起始和结束索引。</p>
<p>函数通过一个for循环从end-1开始向下遍历到start。在每次迭代中,调用popi函数删除当前索引处的元素。popi函数会负责更新Seq结构体的curNum和元素数组,以反映删除操作。</p>
<p>请注意,这个函数假设start和end是有效的索引,且start小于等于end。如果start或end超出了Seq结构体的有效索引范围,或者start大于end,则在调用popi函数时可能会失败。因此,调用cut函数之前,可能需要先检查start和end的有效性。此外,由于popi函数会改变数组的索引,所以在循环中使用end-1到start的范围是为了避免在删除元素时影响到未处理的元素索引。</p>
<h2>修改</h2>
<h3>【修改第i个值】</h3>
<pre><code class="language-c">int set(Seq* s, int i, int n) {
// 检查给定的索引i是否在有效范围内,即是否在0到s-&gt;curNum(当前元素数量)之间
if(i &lt; 0 || i &gt;= s-&gt;curNum) {
// 如果索引i无效,返回1表示操作失败
return 1;
}
// 将索引i处的元素值设置为n
s-&gt;element[i] = n;
// 返回0表示设置操作成功
return 0;
}</code></pre>
<p>这个set函数的目的是在一个Seq结构体中设置指定索引i处的元素值为n。它接受一个指向Seq结构体的指针s、一个整数i(要设置的元素的索引)和一个整数n(新的元素值)作为参数。</p>
<p>函数首先检查索引i是否在有效范围内。如果索引无效(即小于0或大于等于Seq结构体的当前元素数量),函数返回1表示操作失败。如果索引有效,函数将Seq结构体的元素数组中索引i处的元素值设置为n。最后,函数返回0表示设置操作成功。</p>
<p>请注意,这个函数不进行任何内存分配或释放操作,它只是简单地修改了Seq结构体中的一个元素的值。因此,在使用这个函数之前,需要确保Seq结构体已经包含了足够多的元素,且索引i是有效的。</p>
<h3>【替换x为y】</h3>
<pre><code class="language-c">void replace(Seq* s, int x, int y) {
// 定义一个整型变量i,用于在循环中作为索引
int i;
// 遍历Seq结构体中的所有元素
for(i = 0; i &lt; s-&gt;curNum; i++) {
// 检查当前元素是否等于x
if(s-&gt;element[i] == x) {
// 如果找到等于x的元素,将其替换为y
s-&gt;element[i] = y;
}
}
}</code></pre>
<p>这个replace函数的目的是在一个Seq结构体中替换所有等于x的元素为y。它接受一个指向Seq结构体的指针s,以及两个整数x和y作为参数,分别表示要替换的旧值和新值。</p>
<p>函数通过一个for循环遍历Seq结构体中的所有元素。在每次迭代中,函数检查当前元素是否等于x。如果找到等于x的元素,函数将其替换为y。这个操作会更新Seq结构体的元素数组中相应索引处的元素值。</p>
<p>请注意,这个函数会对所有等于x的元素进行替换,而不会停止遍历。如果Seq结构体中没有元素等于x,则函数实际上什么也不做。此外,这个函数不返回任何值,因此调用者无法知道替换操作是否成功或替换了多少个元素。如果需要获取这些信息,函数的设计可能需要进行相应的修改。</p>
<h3>【翻转】</h3>
<pre><code class="language-c">void reverse(Seq* s){ // 定义一个名为reverse的函数,接受一个指向Seq结构的指针作为参数
int n = s-&gt;curNum / 2; // 计算序列当前元素数量的一半,这将是我们需要遍历的最大次数
int i, t, j; // 声明三个整型变量i(循环计数器),t(临时变量用于存储交换前的值),j(序列中对应位置的另一端索引)
for(i=0; i&lt;n; i++){ // 循环遍历直到中间点
j = s-&gt;curNum-1-i; // 计算当前i对应的另一端索引
t = s-&gt;element[i]; // 将当前位置的元素保存到临时变量t中
s-&gt;element[i] = s-&gt;element[j]; // 将另一端的元素复制到当前位置
s-&gt;element[j] = t; // 将临时变量中的值(即原来当前位置的值)赋给另一端的位置
}
}</code></pre>
<p>这个函数假设Seq结构至少有一个整型成员curNum表示序列中的元素数量,并且还有一个数组成员element存储实际的序列数据。该函数不返回任何值(void类型),它直接修改传递给它的序列对象。注意,这里的代码没有做任何错误检查,例如对空指针或非法序列长度的处理,在实际应用中可能需要增加这些检查以提高健壮性。</p>
<h3>查询</h3>
<p>【获取长度】</p>
<pre><code class="language-c">int length(Seq* s){ // 定义一个名为length的函数,接受一个指向Seq结构的指针作为参数
return s-&gt;curNum; // 返回Seq结构中表示当前元素数量的成员变量curNum的值
}
</code></pre>
<p>这个函数非常简单,只有一个返回语句。它通过访问传入的 Seq 对象的 curNum 成员来获取序列的长度,并将其作为结果返回。这里的 s->curNum 表示通过指针 s 访问 Seq 结构体中的 curNum 字段。</p>
<h3>【获取最大容量】</h3>
<pre><code class="language-c">int maxsize(Seq* s){ // 定义一个名为maxsize的函数,接受一个指向Seq结构的指针作为参数
return s-&gt;size; // 返回Seq结构中表示最大容量的成员变量size的值
}</code></pre>
<p>这个函数同样很简单,它返回了 Seq 结构中表示最大容量的成员变量 size 的值。这里假设 Seq 结构中包含一个名为 size 的成员,用来存储序列的最大容量。</p>
<h3>【获取最大值/最小值】</h3>
<pre><code class="language-c">int getMax(Seq* s){ // 定义一个名为getMax的函数,接受一个指向Seq结构的指针作为参数
if(isempty(s)){ // 检查序列是否为空
return -1; // 如果序列为空,则返回-1
}
int max = s-&gt;element[0]; // 初始化最大值为序列的第一个元素
int index = 0; // 初始化最大值的索引为0
int i; // 声明一个循环计数器变量i
for(i=1; i&lt;s-&gt;curNum; i++){ // 遍历从第二个元素到最后一个元素
if(s-&gt;element[i] &gt; max){ // 如果当前元素大于已知的最大值
max = s-&gt;element[i]; // 更新最大值为当前元素
index = i; // 更新最大值的索引为当前元素的索引
}
}
return index; // 返回找到的最大值的索引
}</code></pre>
<p>这个函数首先检查序列是否为空,如果是则返回 -1 表示没有最大值。接着初始化最大值为序列的第一个元素,并将其索引设为 0。然后遍历序列中的所有其他元素,寻找比当前最大值更大的元素。一旦找到更大的元素,就更新最大值及其索引。最后,函数返回最大值的索引。如果序列非空,那么总会返回一个有效的索引值。</p>
<p>最小值略。</p>
<h3>【判断某个值在不在里面】</h3>
<pre><code class="language-c">int has(Seq* s, int n){ // 定义一个名为has的函数,接受一个指向Seq结构的指针和一个整数n作为参数
int i; // 声明一个循环计数器变量i
for(i=0; i&lt;s-&gt;curNum; i++){ // 遍历整个序列,从第一个元素到最后一个元素
if(s-&gt;element[i] == n){ // 如果当前元素等于目标值n
return 1; // 则返回1,表示序列中存在目标值
}
}
return 0; // 如果循环结束都没有找到目标值,则返回0,表示序列中不存在目标值
}</code></pre>
<p>这个函数通过遍历整个序列来查找是否存在与给定值 n 相等的元素。一旦找到相等的元素,函数立即返回 1,表示序列中包含该元素。如果遍历完整个序列都没有找到匹配的元素,则在循环结束后返回 0,表示序列中不包含该元素。</p>
<h3>【获取某个位置的值】</h3>
<pre><code class="language-c">int get(Seq* s, int i, int* res){ // 定义一个名为get的函数,接受一个指向Seq结构的指针、一个整数索引i和一个指向整数的指针res
if(i&lt;0 || i&gt;= s-&gt;curNum){ // 检查索引i是否越界(小于0或大于等于当前元素数量)
return 1; // 如果索引越界,返回1表示错误
}
*res = s-&gt;element[i]; // 如果索引有效,将索引i对应的元素值赋给res所指向的内存位置
return 0; // 返回0表示操作成功
}
</code></pre>
<p>这个函数的作用是安全地获取序列中指定索引的元素值。首先检查索引是否在合法范围内(即 0 <= i < s->curNum)。如果索引超出范围,则返回 1 表示有错误发生。如果索引有效,则通过解引用指针 res 将找到的元素值存入,并返回 0 表示操作成功。这样做的好处是可以避免因索引越界而导致程序崩溃或其他未定义行为。</p>
<h3>【获取某个值的位置】</h3>
<pre><code class="language-c">int index_(Seq* s, int n){ // 定义一个名为index_的函数,接受一个指向Seq结构的指针和一个整数n作为参数
int i; // 声明一个循环计数器变量i
for(i=0; i&lt;s-&gt;curNum; i++){ // 遍历整个序列,从第一个元素到最后一个元素
if(s-&gt;element[i] == n){ // 如果当前元素等于目标值n
return i; // 则返回当前元素的索引
}
}
return -1; // 如果循环结束都没有找到目标值,则返回-1,表示序列中不存在目标值
}</code></pre>
<p>这个函数通过遍历整个序列来查找是否存在与给定值 n 相等的元素。一旦找到相等的元素,函数立即返回该元素的索引。如果遍历完整个序列都没有找到匹配的元素,则在循环结束后返回 -1,表示序列中不包含该元素。这样的实现确保了即使序列中有多个相同的元素,返回的也是第一次出现的那个元素的索引。</p>