目錄
一、順序表有什么功能?
二、實(shí)現(xiàn)順序表的各個(gè)功能
1.前置準(zhǔn)備
2.初始化順序表
3.順序表擴(kuò)容
4.打印順序表
5.增加順序表成員
5.1尾增
5.2頭增
?6.刪除順序表中成員的內(nèi)容
6.1尾刪
6.2頭刪
?7.查找成員
?8.修改(替換)
9.插入(在目標(biāo)位置插入成員)
10.定向刪除(將目標(biāo)位置的成員刪除)
三、全部代碼
1.函數(shù)頭文件
2.函數(shù)實(shí)現(xiàn)
一、順序表有什么功能?
這就像是大綱一樣,只要我們明確了要實(shí)現(xiàn)的功能,之后就是努力地實(shí)現(xiàn)它們就好了,眾所周知,順序表是在計(jì)算機(jī)內(nèi)存中以數(shù)組的形式保存我們需要的數(shù)據(jù)。既然數(shù)據(jù)被保存了,那么我們接下來就是對(duì)這些保存好的數(shù)據(jù)進(jìn)行對(duì)應(yīng)的操作,增刪改查是必須要有的,接著,我們想將順序表中的內(nèi)容打印出來,看看到底有沒有正確的存儲(chǔ)我們需要的數(shù)據(jù),我們可以再設(shè)計(jì)一個(gè)打印函數(shù),想對(duì)順序表的內(nèi)容排序也可以再設(shè)計(jì)一個(gè)排序函數(shù),反正根據(jù)自己所需設(shè)計(jì),但是增刪改查是最基本的,必須要有的。
二、實(shí)現(xiàn)順序表的各個(gè)功能
1.前置準(zhǔn)備
在實(shí)現(xiàn)順序表的各個(gè)功能之前我們得先有點(diǎn)前置準(zhǔn)備內(nèi)容,順序表的成員類型,順序表這個(gè)結(jié)構(gòu)體的設(shè)計(jì),頭文件的引用......這些操作筆者推薦都放在一個(gè)頭文件中進(jìn)行,這樣在調(diào)用的時(shí)候僅需引用一個(gè)頭文件即可完成我們需要的功能。
// SeqList.h
//將所需函數(shù)和所需頭文件的引用放在一個(gè)頭文件中,那么在使用的時(shí)候就只用引用一個(gè)頭文件
#pragma once//防止頭文件被重復(fù)引用
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//可能要用到的頭文件
typedef int SlDateType;
//將int typedef成SlDateType這樣就可以區(qū)分int和順序表成員
// 雖然它們的類型本質(zhì)上都是int但是它們的字面含義已經(jīng)不同
//當(dāng)然了,可以把int換成別的類型
//這樣子設(shè)計(jì)其實(shí)更多的是為了到時(shí)順序表成員類型想更換直接從這換就全換了,不用一個(gè)一個(gè)換
typedef struct seqlist
{
SlDateType* a;
//創(chuàng)建一個(gè)指針類型的順序表成員數(shù)據(jù),為什么是指針?
//這樣做是為了到時(shí)能夠使用malloc和realloc對(duì)空間的大小進(jìn)行開辟與修改
//相當(dāng)于柔性數(shù)組
int sz;//已經(jīng)存放了多少個(gè)成員
int capacity;//容量大小,以后判定空間是否夠用可以通過這個(gè)來判定
}seqlist;//將結(jié)構(gòu)體名字命名為seqlist,使用時(shí)更加方便
2.初始化順序表
記得在書寫代碼之前將之前的順序表頭文件引用進(jìn)來,這樣就可以用到順序表頭文件的內(nèi)容。
//順序表.c
#include"順序表.h"
void init_seqlist(seqlist* s1)//通過指針的形式訪問,便能夠?qū)?nèi)容進(jìn)行修改
{
s1->capacity = 3;//將容量大小初始化為3,為了更好地測(cè)試到時(shí)的擴(kuò)容效果
s1->sz = 0;//將成員數(shù)量初始化為0,代表著此時(shí)沒有存放成員
s1->a = (SlDateType*)malloc(sizeof(SlDateType) * s1->capacity);
//將順序表的成員數(shù)組大小初始化和容量一樣的大小
if (s1->a == NULL)//開辟失敗的話直接退出程序
{
exit(-1);
}
}
在順序表.c中書寫完函數(shù)的內(nèi)容后別忘了在順序表.h中引用它,這樣別人才能夠只引用一個(gè)頭文件就能夠使用對(duì)應(yīng)函數(shù)。
3.順序表擴(kuò)容
在存放順序表成員之前我們應(yīng)該要注意的一點(diǎn)就是,我們的容量是有限的,那么在觸及容量的時(shí)候,也就是順序表已經(jīng)被裝滿的時(shí)候,我們應(yīng)該要擴(kuò)容處理,避免出現(xiàn)裝不下內(nèi)容的情況出現(xiàn)。
void if_enough(seqlist* s1)
{
if (s1->sz == s1->capacity)
//當(dāng)容量和成員個(gè)數(shù)相當(dāng)時(shí),顯然就已經(jīng)存滿了,需要擴(kuò)容
{
s1->a = realloc(s1->a,sizeof(SlDateType)*s1->capacity*2);
//將容量擴(kuò)大到原來容量的兩倍
if (s1->a == NULL)
{
perror("if_enough");//錯(cuò)誤提示
return;//中止程序
}
s1->capacity *= 2;//擴(kuò)容成功,容量翻倍
printf("擴(kuò)容成功,當(dāng)前容量為%d\n",s1->capacity);//擴(kuò)容成功給個(gè)提示
}
}
4.打印順序表
在增加之前,我們就會(huì)意識(shí)到這樣一個(gè)問題,倘若我增加了順序表成員,但我又該如何分辨出我成功增加了順序表成員呢,聽著是不是很繞?其實(shí)就是我們不能夠直接的看到順序表的內(nèi)容,因此我們可以使用打印的方式將順序表的內(nèi)容打印出來。
void print_seqlist(const seqlist* s1)
//將內(nèi)容打印出來,但內(nèi)容是不會(huì)被改變的,因此用const修飾,避免內(nèi)容被修改
{
if (s1->sz == 0)
{
printf("順序表為空,操作失敗\n");
return;
}
int i = 0;
for (i = 0; i < s1->sz; i++)
{
printf("%d ", s1->a[i]);//將內(nèi)容通過循環(huán)的方式打印出來
}
printf("\n");//打印完所有內(nèi)容之后最好換行
}
5.增加順序表成員
5.1尾增
什么是尾增?顧名思義,就是從最后面開始增加,即在順序表的最后進(jìn)行成員的添加,注意:在進(jìn)行增加之前我們需要判斷順序表是否被放滿,這個(gè)時(shí)候就可以使用我們之前創(chuàng)建的if_enough函數(shù)來判斷是否需要進(jìn)行擴(kuò)容處理,如果需要?jiǎng)t擴(kuò)容,不需要?jiǎng)t無(wú)事發(fā)生。
void seqlist_pushback(seqlist*s1,SlDateType x)
{
if_enough(s1);
s1->a[s1->sz] = x;//在順序表的最后插入一個(gè)數(shù)據(jù)x
s1->sz++;
}
創(chuàng)建一個(gè)新的文件,測(cè)試一下我們之前寫的代碼?
//test.c
#include"順序表.h"
int main()
{
seqlist s1;
init_seqlist(&s1);//初始化順序表
print_seqlist(&s1);
//將順序表內(nèi)容打印,但此時(shí)是空,故不能打印
seqlist_pushback(&s1, 1);//依次將1,2,3放入順序表中
seqlist_pushback(&s1, 2);
seqlist_pushback(&s1, 3);
print_seqlist(&s1);//打印順序表
seqlist_pushback(&s1, 2);//依次將2,3放入順序表中
seqlist_pushback(&s1, 3);
print_seqlist(&s1);//打印順序表
}
5.2頭增
顧名思義,在順序表的最開始進(jìn)行成員的增加,我們不難想象,若是這個(gè)順序表中已經(jīng)有成員了這么辦?難不成直接將這個(gè)成員替換成我們的目標(biāo)?如果這樣做就會(huì)少一個(gè)成員,根據(jù)數(shù)組的經(jīng)驗(yàn),我們只能夠通過覆蓋的方式先將所有的成員往后挪一個(gè)單位,再將最前面的成員替換成我們需要的成員。同樣在開始之前我們應(yīng)該要判斷容量是否足夠。
這里挪動(dòng)是核心,同樣也是一門學(xué)問,筆者在這畫副圖給大家,大家就懂得如何挪動(dòng)了
?由圖可知,我們要先將最后面的成員往后挪動(dòng)到下一個(gè)空間中,也就是sz對(duì)應(yīng)的空間內(nèi)容,得是sz-1的空間內(nèi)容,sz-1的內(nèi)容得是sz-2的內(nèi)容,那么就可以通過循環(huán)的方式實(shí)現(xiàn),sz-i指向的內(nèi)容等于sz-i-1指向的內(nèi)容,i實(shí)現(xiàn)一步步的覆蓋,這里面比較難想的就是i的范圍,由目標(biāo)分析可知,當(dāng)sz-i-1=0的時(shí)候結(jié)束循環(huán),為什么?,因?yàn)楫?dāng)sz-i-1=0的時(shí)候,sz-i等于1,也就是1對(duì)應(yīng)的目標(biāo),等于0對(duì)應(yīng)的目標(biāo),完成這一步之后,所有的覆蓋就已經(jīng)結(jié)束,根據(jù)計(jì)算可知,i=sz-1,故i<sz便可以實(shí)現(xiàn)所有的覆蓋。
void seqlist_pushfront(seqlist* s1, SlDateType x)
{
if_enough(s1);
int i = 0;
for (i=0;i<s1->sz;i++)//通過循環(huán)從后往前覆蓋
{
s1->a[s1->sz - i] = s1->a[s1->sz-i-1];
}
s1->a[0] = x;//將首元素替換成x
s1->sz++;
}
?同樣可以測(cè)試一下
//test.c
#include"順序表.h"
int main()
{
seqlist s1;
init_seqlist(&s1);//初始化順序表
print_seqlist(&s1);
//將順序表內(nèi)容打印,但此時(shí)是空,故不能打印
seqlist_pushback(&s1, 1);//依次將1,2,3放入順序表中
seqlist_pushback(&s1, 2);
seqlist_pushback(&s1, 3);
print_seqlist(&s1);//打印順序表
seqlist_pushfront(&s1,520);//在最前面放入520
print_seqlist(&s1);//打印順序表
}
?6.刪除順序表中成員的內(nèi)容
6.1尾刪
這個(gè)就很簡(jiǎn)單了,我們只需要將此時(shí)順序表的成員數(shù)量往回?fù)芤晃痪托小槭裁??舉個(gè)例子,成員中已經(jīng)有了1,2,3,4,5那么不難得出sz此時(shí)是5,指向的是5后面的空間,而當(dāng)我們把數(shù)量往回?fù)艿脑?,sz就指向了4,那么此時(shí)sz就指向了5對(duì)應(yīng)的空間,下次你在再增加內(nèi)容的時(shí)候這個(gè)空間就會(huì)被自動(dòng)覆蓋掉,同樣,打印的話也是根據(jù)sz來打印的,會(huì)直接略過。唯一需要注意的一點(diǎn)就是,當(dāng)順序表的成員為空的時(shí)候,也就是沒有成員的時(shí)候,強(qiáng)行刪除的話就會(huì)造成越界問題的發(fā)生。因?yàn)闆]有成員的時(shí)候,sz為0,你對(duì)它強(qiáng)行進(jìn)行刪除,那么就會(huì)導(dǎo)致sz=-1,下一次再增加元素的時(shí)候,就會(huì)越界訪問。
void seqlist_popback(seqlist* s1)
{
if (s1->sz == 0)
{
printf("順序表為空,操作失敗\n");
return;
}
s1->sz--;
}
6.2頭刪
頭刪相對(duì)于尾刪麻煩一些,我們通過從前往后覆蓋的方式將前面的內(nèi)容覆蓋成后面的內(nèi)容
void seqlist_popfront(seqlist* s1)
{
if (s1->sz == 0)
{
printf("順序表為空,操作失敗\n");
return;
}
int i = 0;
for (i = 1; i < s1->sz; i++)
{
s1->a[i-1] = s1->a[i];//從前往后覆蓋
}
s1->sz--;
}
同樣,我們可以測(cè)試一下?
?7.查找成員
目標(biāo)很簡(jiǎn)單,就是查找到目標(biāo)成員然后打印出來,找不到就打印找不到,通過一次遍歷就可以搞定
void seqlist_fine(const seqlist* s1,const SlDateType x)
//查找的目標(biāo)是x,用const修飾是因?yàn)橹皇遣檎?,不用修?{
if (s1->sz == 0)
{
printf("順序表為空,操作失敗\n");
return;
}
int i = 0;
for (i = 0;i<s1->sz; i++)
{
if (s1->a[i] == x)//相等意味著找到了
{
printf("找到%d了,下標(biāo)為%d\n",x,i);
return;
}
}
printf("目標(biāo)不存在\n");
}
同樣可以測(cè)試一下?
?8.修改(替換)
給對(duì)應(yīng)的下標(biāo),和被修改的結(jié)果,對(duì)目標(biāo)下標(biāo)的內(nèi)容進(jìn)行修改,要注意的是,我們修改下標(biāo)的范圍只能是在成員組中進(jìn)行修改,什么意思?就是說,我們不能對(duì)還沒放成員的下標(biāo)進(jìn)行修改
void seqlist_modify(seqlist* s1, int pos, const SlDateType x)
{
if (pos >= s1->sz)
//當(dāng)pos=sz時(shí)就已經(jīng)是對(duì)還不是成員的空間進(jìn)行操作了,更別說后面的了
{
printf("當(dāng)前空間還不是成員的一部分,操作失敗\n");
return;
}
s1->a[pos] = x;
}
同樣可以測(cè)試一下
9.插入(在目標(biāo)位置插入成員)
需要注意的便是,我們插入的范圍是多少,很顯然0~sz-1都是可以插入的,這里面已經(jīng)是有內(nèi)容的了,那么sz可不可以呢?可以,因?yàn)樵趕z這個(gè)位置插入就相當(dāng)于尾插,還有一點(diǎn)需要注意,那便是插入成員,成員的數(shù)量是會(huì)增加的,那么也就是說,我們一樣要在插入前判斷是否需要擴(kuò)容。
void seqlist_insert(seqlist* s1, int pos, const SlDateType x)
{
if_enough(s1);
if (pos > s1->sz)//比sz還大,意味著插入的位置會(huì)導(dǎo)致連續(xù)性被破壞
{
printf("插入位置出錯(cuò),操作失敗\n");
return;
}
int i = 0;
for (i = 0;i<s1->sz-pos; i++)
{
s1->a[s1->sz-i] = s1->a[s1->sz-i-1];//從后向前覆蓋
}
s1->a[pos] = x;
s1->sz++;
}
測(cè)試一下
10.定向刪除(將目標(biāo)位置的成員刪除)
有了之前插入的經(jīng)驗(yàn),這個(gè)就顯得很簡(jiǎn)單,但要注意的一點(diǎn)則是,它的刪除范圍只能是0~sz-1,sz不被包括在內(nèi),因?yàn)閟z顯而易見還不是成員。
void seqlist_erase(seqlist* s1, int pos)
{
if (pos >= s1->sz)//等于sz時(shí)就已經(jīng)是在刪除未被定義的內(nèi)容了
{
printf("刪除位置出錯(cuò),操作失敗\n");
return;
}
int i = 0;
for (i=0;pos+i+1<s1->sz;i++)
{
s1->a[pos+i] = s1->a[pos+i+1];//從前向后覆蓋
}
s1->sz--;
}
測(cè)試一下
?當(dāng)我們完成了插入和定向刪除,其實(shí)之前的頭插頭刪,尾插尾刪都可以通過這兩個(gè)函數(shù)來替換,這里就不再一一展示,升級(jí)版直接放在全部代碼里面。文章來源:http://www.zghlxwxcb.cn/news/detail-612317.html
三、全部代碼
1.函數(shù)頭文件
// SeqList.h
//將所需函數(shù)和所需頭文件的引用放在一個(gè)頭文件中,那么在使用的時(shí)候就只用引用一個(gè)頭文件
#pragma once//防止頭文件被重復(fù)引用
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//可能要用到的頭文件
typedef int SlDateType;
//將int typedef成SlDateType這樣就可以區(qū)分int和順序表成員
// 雖然它們的類型本質(zhì)上都是int但是它們的字面含義已經(jīng)不同
//當(dāng)然了,可以把int換成別的類型
//這樣子設(shè)計(jì)其實(shí)更多的是為了到時(shí)順序表成員類型想更換直接從這換就全換了,不用一個(gè)一個(gè)換
typedef struct seqlist
{
SlDateType* a;
//創(chuàng)建一個(gè)指針類型的順序表成員數(shù)據(jù),為什么是指針?
//這樣做是為了到時(shí)能夠使用malloc和realloc對(duì)空間的大小進(jìn)行開辟與修改
//相當(dāng)于柔性數(shù)組
int sz;//已經(jīng)存放了多少個(gè)成員
int capacity;//容量大小,以后判定空間是否夠用可以通過這個(gè)來判定
}seqlist;//將結(jié)構(gòu)體名字命名為seqlist,使用時(shí)更加方便
//初始化順序表
void init_seqlist(seqlist*s1);
//打印順序表
void print_seqlist(const seqlist* s1);
//尾增
void seqlist_pushback(seqlist* s1, SlDateType x);
//頭增
void seqlist_pushfront(seqlist* s1, SlDateType x);
//尾刪
void seqlist_popback(seqlist* s1);
//頭刪
void seqlist_popfront(seqlist* s1);
//查找成員
void seqlist_fine(const seqlist* s1,const SlDateType x);
//修改成員
void seqlist_modify(seqlist* s1, int pos, const SlDateType x);
//插入成員
void seqlist_insert(seqlist* s1, int pos, const SlDateType x);
//刪除成員
void seqlist_erase(seqlist* s1, int pos);
2.函數(shù)實(shí)現(xiàn)
//順序表.c
#include"順序表.h"
void init_seqlist(seqlist* s1)//通過指針的形式訪問,便能夠?qū)?nèi)容進(jìn)行修改
{
s1->capacity = 3;//將容量大小初始化為3,為了更好地測(cè)試到時(shí)的擴(kuò)容效果
s1->sz = 0;//將成員數(shù)量初始化為0,代表著此時(shí)沒有存放成員
s1->a = (SlDateType*)malloc(sizeof(SlDateType) * s1->capacity);
//將順序表的成員數(shù)組大小初始化和容量一樣的大小
if (s1->a == NULL)//開辟失敗的話直接退出程序
{
exit(-1);
}
}
void if_enough(seqlist* s1)
{
if (s1->sz == s1->capacity)
//當(dāng)容量和成員個(gè)數(shù)相當(dāng)時(shí),顯然就已經(jīng)存滿了,需要擴(kuò)容
{
s1->a = realloc(s1->a,sizeof(SlDateType)*s1->capacity*2);
//將容量擴(kuò)大到原來容量的兩倍
if (s1->a == NULL)
{
perror("if_enough");//錯(cuò)誤提示
return;//中止程序
}
s1->capacity *= 2;//擴(kuò)容成功,容量翻倍
printf("擴(kuò)容成功,當(dāng)前容量為%d\n",s1->capacity);//擴(kuò)容成功給個(gè)提示
}
}
void print_seqlist(const seqlist* s1)
//將內(nèi)容打印出來,但內(nèi)容是不會(huì)被改變的,因此用const修飾,避免內(nèi)容被修改
{
if (s1->sz == 0)
{
printf("順序表為空,操作失敗\n");
return;
}
int i = 0;
for (i = 0; i < s1->sz; i++)
{
printf("%d ", s1->a[i]);//將內(nèi)容通過循環(huán)的方式打印出來
}
printf("\n");//打印完所有內(nèi)容之后最好換行
}
void seqlist_pushback(seqlist*s1,SlDateType x)
{
//if_enough(s1);
//s1->a[s1->sz] = x;//在順序表的最后插入一個(gè)數(shù)據(jù)x
//s1->sz++;
seqlist_insert(s1,s1->sz,x);
}
void seqlist_pushfront(seqlist* s1, SlDateType x)
{
//if_enough(s1);
//int i = 0;
//for (i=0;i<s1->sz;i++)//通過循環(huán)從后往前覆蓋
//{
// s1->a[s1->sz - i] = s1->a[s1->sz-i-1];
//}
//s1->a[0] = x;//將首元素替換成x
//s1->sz++;
seqlist_insert(s1,0, x);
}
void seqlist_popback(seqlist* s1)
{
/*if (s1->sz == 0)
{
printf("順序表為空,操作失敗\n");
return;
}
s1->sz--;*/
seqlist_erase(s1,s1->sz-1);
}
void seqlist_popfront(seqlist* s1)
{
//if (s1->sz == 0)
//{
// printf("順序表為空,操作失敗\n");
// return;
//}
//int i = 0;
//for (i = 1; i < s1->sz; i++)
//{
// s1->a[i-1] = s1->a[i];//從前往后覆蓋
//}
//s1->sz--;
seqlist_erase(s1,0);
}
void seqlist_fine(const seqlist* s1,const SlDateType x)
//查找的目標(biāo)是x,用const修飾是因?yàn)橹皇遣檎遥挥眯薷?{
if (s1->sz == 0)
{
printf("順序表為空,操作失敗\n");
return;
}
int i = 0;
for (i = 0;i<s1->sz; i++)
{
if (s1->a[i] == x)//相等意味著找到了
{
printf("找到%d了,下標(biāo)為%d\n",x,i);
return;
}
}
printf("目標(biāo)不存在\n");
}
void seqlist_modify(seqlist* s1, int pos, const SlDateType x)
{
if (pos >= s1->sz)
//當(dāng)pos=sz時(shí)就已經(jīng)是對(duì)還不是成員的空間進(jìn)行操作了,更別說后面的了
{
printf("當(dāng)前空間還不是成員的一部分,操作失敗\n");
return;
}
s1->a[pos] = x;
}
void seqlist_insert(seqlist* s1, int pos, const SlDateType x)
{
if_enough(s1);
if (pos > s1->sz)//比sz還大,意味著插入的位置會(huì)導(dǎo)致連續(xù)性被破壞
{
printf("插入位置出錯(cuò),操作失敗\n");
return;
}
int i = 0;
for (i = 0;i<s1->sz-pos; i++)
{
s1->a[s1->sz-i] = s1->a[s1->sz-i-1];//從后向前覆蓋
}
s1->a[pos] = x;
s1->sz++;
}
void seqlist_erase(seqlist* s1, int pos)
{
if (pos >= s1->sz)//等于sz時(shí)就已經(jīng)是在刪除未被定義的內(nèi)容了
{
printf("刪除位置出錯(cuò),操作失敗\n");
return;
}
int i = 0;
for (i=0;pos+i+1<s1->sz;i++)
{
s1->a[pos+i] = s1->a[pos+i+1];//從前向后覆蓋
}
s1->sz--;
}
好了,今天的分享到這里就結(jié)束了,感謝各位友友的來訪,祝各位友友前程似錦O(∩_∩)O文章來源地址http://www.zghlxwxcb.cn/news/detail-612317.html
到了這里,關(guān)于手把手教你怎么寫順序表的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!