C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組模擬實(shí)現(xiàn)順序表流程詳解
代碼已經(jīng)放在Gitee上,需要可以小伙伴可以去看看
用C語(yǔ)言數(shù)組模擬實(shí)現(xiàn)順序表
線性表和順序表
線性表
線性表(linear list)是n個(gè)具有相同特性的數(shù)據(jù)元素的有限序列,這是我們廣泛使用的數(shù)據(jù)結(jié)構(gòu)。
線性表在邏輯上是線性結(jié)構(gòu),也就說(shuō)是連續(xù)的一條直線。但是在物理結(jié)構(gòu)上并不一定是連續(xù)的,線性表在物理上存儲(chǔ)時(shí),通常以數(shù)組和鏈?zhǔn)浇Y(jié)構(gòu)的形式存儲(chǔ)。
常見(jiàn)的線性表:順序表、鏈表、棧、隊(duì)列、字符串…

順序表
順序表是用一段物理地址連續(xù)的存儲(chǔ)單元依次存儲(chǔ)數(shù)據(jù)元素的線性結(jié)構(gòu),一般情況下采用數(shù)組存儲(chǔ)。在數(shù)組上完成數(shù)據(jù)的增刪查改。
一般可以分為:
- 靜態(tài)順序表:使用定長(zhǎng)數(shù)組來(lái)存儲(chǔ)元素
- 動(dòng)態(tài)順序表:使用動(dòng)態(tài)開(kāi)辟的數(shù)組來(lái)儲(chǔ)存元素
靜態(tài)順序表
//定義靜態(tài)數(shù)組的大小,方便后續(xù)修改
#define MAX_SIZE 50
//重命名數(shù)組的數(shù)據(jù)類(lèi)型,方便后續(xù)修改
typedef int SLDataType;
//定義結(jié)構(gòu)體
//成員變量為數(shù)組和記錄當(dāng)前數(shù)據(jù)個(gè)數(shù)的變量
//重命名結(jié)構(gòu)體數(shù)據(jù)類(lèi)型,方便書(shū)寫(xiě)
typedef struct SeqList {
SLDataType arr[MAX_SIZE];
int size;
}SL;
//-----------------------------------------------------------------------------
//以下是一些常見(jiàn)的接口的聲明
//順序表初始化
//利用結(jié)構(gòu)體類(lèi)型創(chuàng)建一個(gè)靜態(tài)順序表變量后,可以對(duì)其進(jìn)行初始化
void SLInit(SL* psl);
//打印順序表
//把順序表的值按照先后順序打印出來(lái)
void SLPrint(SL* psl);
//檢查順序表是否已滿(mǎn)
//每次進(jìn)行加入數(shù)據(jù)的操作的時(shí)候需要先檢查是否已經(jīng)滿(mǎn)了,如果滿(mǎn)了就不能夠插入了
void SLCheck(SL* psl);
//順序表的尾插
//在順序表的尾部在插入一個(gè)元素
//由于是數(shù)組加入數(shù)據(jù)很方便,直接使用數(shù)組下標(biāo)就可以訪問(wèn)到
void SLPushBack(SL* psl, SLDataType data);
//順序表的尾刪
//刪除順序表尾部的數(shù)據(jù)
void SLPopBack(SL* psl);
//順序表的頭插
//在順序表的開(kāi)頭加入一個(gè)數(shù)據(jù)
void SLPushFront(SL* psl, SLDataType data);
//順序表的頭刪
//把順序表第一位數(shù)據(jù)刪除
void SLPopFront(SL* psl);
//順序表查找某個(gè)數(shù)據(jù)
//查找順序表中是否存在某個(gè)數(shù)據(jù),如果有就返回對(duì)應(yīng)的下標(biāo)
//如果找不到就返回-1
int SLFind(SL* psl, SLDataType x);
//順序表在pos位置插入x
//在指定下標(biāo)位置插入數(shù)據(jù)x,原來(lái)x位置的數(shù)據(jù)以及后面的數(shù)據(jù)往后移動(dòng)
void SLInsert(SL* psl, size_t pos, SLDataType x);
//順序表刪除在pos位置的數(shù)據(jù)
void SLErase(SL* psl, size_t pos);
//順序表某一位置數(shù)據(jù)的修改
void SLModify(SL* psl, size_t pos, SLDataType x);
以下是這些接口的具體實(shí)現(xiàn)
//順序表初始化
void SLInit(SL* psl) {
psl->arr[0] = 0;//此處只能初始化一個(gè)元素
psl->size = 0;
}
//打印順序表
void SLPrint(SL* psl) {
int i = 0;
if (psl->size) {
for (i = 0; i < psl->size; i++) {
//輸出格式,記得根據(jù)SLDataTyped的類(lèi)型來(lái)修改
printf("%d ", psl->arr[i]);
}
printf("\n");
}
else {
printf("Null\n");
}
}
/*
//檢查順序表是否已滿(mǎn)
void SLCheck(SL* psl) {
if (psl->size == MAX_SIZE) {
printf("順序表已滿(mǎn),無(wú)法進(jìn)行后續(xù)操作");
}
}
*/
//順序表的尾插
void SLPushBack(SL* psl, SLDataType data) {
//插入數(shù)據(jù)要先檢查空間是否已滿(mǎn)
//實(shí)現(xiàn)方法一不夠好
/*
if (psl->size == MAX_SIZE) {
printf("空間已滿(mǎn)\n");
return;
}
else {
psl->arr[psl->size] = data;
psl->size++;
}*/
//實(shí)現(xiàn)方法二,簡(jiǎn)單明了
assert(psl->size != MAX_SIZE);
psl->arr[psl->size] = data;
psl->size++;
}
//順序表的尾刪
void SLPopBack(SL* psl) {
//判斷是否還有元素可以刪除
assert(psl->size);
psl->size--;
}
//順序表的頭插
void SLPushFront(SL* psl, SLDataType data) {
assert(psl->size != MAX_SIZE);
//src用來(lái)后移數(shù)據(jù)
int src = psl->size;
while (src >= 1) {
psl->arr[src] = psl->arr[src - 1];
src--;
}
psl->arr[src] = data;
psl->size++;
}
//順序表的頭刪
void SLPopFront(SL* psl) {
//判斷是否還有數(shù)據(jù)可以刪除
assert(psl->size);
int src = 0;
while (src < psl->size - 1) {
psl->arr[src] = psl->arr[src + 1];
src++;
}
psl->size--;
}
//順序表查找某個(gè)數(shù)據(jù)
int SLFind(SL* psl, SLDataType x) {
int i = 0;
for (i = 0; i < psl->size; i++) {
if (psl->arr[i] == x) {
//找到了就返回該數(shù)據(jù)在順序表中的位置
return i;
}
}
//找不到就返回-1
return -1;
}
//順序表在pos位置插入x
void SLInsert(SL* psl, size_t pos, SLDataType x) {
assert(psl->size < MAX_SIZE);
assert(pos >= 0 && pos <= psl->size);//pos=0或者pos=size的時(shí)候,相當(dāng)于頭插,尾插
int end = psl->size;
while (end > pos) {
psl->arr[end] = psl->arr[end - 1];
end--;
}
psl->arr[pos] = x;
psl->size++;
}
//順序表刪除在pos位置的數(shù)據(jù)
void SLErase(SL* psl, size_t pos) {
assert(psl->size);
assert(pos >= 0 && pos < psl->size);
int start = pos + 1;
while (start < psl->size) {
psl->arr[start - 1] = psl->arr[start];
start++;
}
psl->size--;
}
//順序表某一位置數(shù)據(jù)的修改
void SLModify(SL* psl, size_t pos, SLDataType x) {
assert(psl->size);
assert(pos >= 0 && pos < psl->size);
psl->arr[pos] = x;
}
上面代碼的測(cè)試,我放在了Gitee上,需要的小伙伴可以參考一下
動(dòng)態(tài)順序表
靜態(tài)順序表只適用于確定知道需要存多少數(shù)據(jù)的場(chǎng)景。靜態(tài)順序表的定長(zhǎng)數(shù)組導(dǎo)致N定大了,空間開(kāi)多了浪費(fèi),開(kāi)少了不夠用。所以現(xiàn)實(shí)中基本都是使用動(dòng)態(tài)順序表,根據(jù)需要?jiǎng)討B(tài)的分配空間大小,所以下面我們實(shí)現(xiàn)動(dòng)態(tài)順序表。
//重命名SL的數(shù)據(jù)類(lèi)型,方便后續(xù)修改
typedef int SLDataType;
//定義結(jié)構(gòu)體
//成員變量為指向動(dòng)態(tài)順序表的指針,數(shù)據(jù)的個(gè)數(shù),順序表的容量
//capacity用來(lái)管理數(shù)組的總大小,如果size與capacity相等了,就表示數(shù)組已經(jīng)滿(mǎn)了需要擴(kuò)容
//重定義結(jié)構(gòu)體類(lèi)型名稱(chēng),方便操作
typedef struct SeqList {
SLDataType* p;
int size;
int capacity;
}SL;
//----------------------------------------------------------------------
//一下是一些常用的接口,與靜態(tài)順序表差不多
//SL初始化
void SLInit(SL* ps);
//SL空間檢查
//如若size與capacity相等表示數(shù)組已經(jīng)滿(mǎn)了,需要擴(kuò)容
void SLCheckCapacity(SL* ps);
//SL打印
void SLPrint(SL* ps);
//SL銷(xiāo)毀
//因?yàn)閿?shù)組是動(dòng)態(tài)開(kāi)辟的,所以在最后不使用的數(shù)組的時(shí)候要釋放空間
void SLDestory(SL* ps);
//SL尾插
void SLPushBack(SL* ps,SLDataType x);
//SL尾刪
void SLPopBack(SL* ps);
//SL頭插
void SLPushFront(SL* ps, SLDataType x);
//SL頭刪
void SLPopFront(SL* ps);
//SL查找某個(gè)數(shù)據(jù)
//如果能找到,返回該數(shù)據(jù)在順序表中下標(biāo)
int SLFind(SL* ps, SLDataType x);
//SL在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDataType x);
//SL刪除pos位置的值
void SLErase(SL* ps, size_t pos);
//SL修改某一位置的數(shù)據(jù)
void SLModity(SL* ps, size_t pos, SLDataType x);
以下是具體的實(shí)現(xiàn)
//動(dòng)態(tài)順序表的實(shí)現(xiàn)
#include"DynamicSeqList.h"
//SL初始化
void SLInit(SL* ps) {
ps->p = NULL;
ps->capacity = 0;
ps->size = 0;
}
//SL空間檢查
void SLCheckCapacity(SL* ps) {
if (ps->size == ps->capacity) {
ps->capacity = (ps->capacity == 0) ? 5 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->p, (ps->capacity) * sizeof(SLDataType));
if (tmp == NULL) {
printf("realloc fail\n");
exit(-1);
}
ps->p = tmp;
}
}
//SL打印
void SLPrint(SL* ps) {
if (ps->size == 0) {
printf("順序表為空\(chéng)n");
}
else {
int i = 0;
for (i = 0; i < ps->size; i++) {
//打印格式記得根據(jù)SLDataType的類(lèi)型來(lái)修改
printf("%d ", ps->p[i]);
}
printf("\n");
}
}
//SL銷(xiāo)毀
//這里并沒(méi)有完全銷(xiāo)毀結(jié)構(gòu)體s,只是把成員變量都賦值為0
void SLDestory(SL* ps) {
free(ps->p);
ps->p = NULL;
ps->size = ps->capacity = 0;
}
//SL尾插
void SLPushBack(SL* ps, SLDataType x) {
SLCheckCapacity(ps);
ps->p[ps->size] = x;
ps->size++;
}
//SL尾刪
void SLPopBack(SL* ps) {
//刪除數(shù)據(jù)需要判斷一下順序表是否為空
assert(ps->size > 0);
ps->size--;
}
//SL頭插
void SLPushFront(SL* ps, SLDataType x) {
SLCheckCapacity(ps);
int end = ps->size;
while (end > 0) {
ps->p[end] = ps->p[end - 1];
end--;
}
ps->p[end] = x;
ps->size++;
}
//SL頭刪
void SLPopFront(SL* ps) {
//刪除數(shù)據(jù)需要判斷一下順序表是否為空
assert(ps->size > 0);
int start = 0;
while (start < ps->size - 1) {
ps->p[start] = ps->p[start + 1];
start++;
}
ps->size--;
}
//SL查找某個(gè)數(shù)據(jù)
int SLFind(SL* ps, SLDataType x) {
//需要判斷順序表是否為空,可以用assert,也可以用if判斷
assert(ps->size);
int i = 0;
for (i = 0; i < ps->size; i++) {
if (x == ps->p[i]) {
return i;
}
}
return -1;
}
//SL在pos位置插入x
//當(dāng)pos為0或者pos為size時(shí),相當(dāng)于頭插、尾插
void SLInsert(SL* ps, size_t pos, SLDataType x) {
SLCheckCapacity(ps);
assert(pos >= 0 && pos <= ps->size);
int end = ps->size;
while (end > pos) {
ps->p[end] = ps->p[end - 1];
end--;
}
ps->p[end] = x;
ps->size++;
}
//SL刪除pos位置的值
void SLErase(SL* ps, size_t pos) {
//判斷要?jiǎng)h除的位置是否在size之內(nèi)
assert(pos >= 0 && pos < ps->size);
int start = pos + 1;
while (start < ps->size) {
ps->p[start - 1] = ps->p[start];
start++;
}
ps->size--;
}
//SL修改某一位置的數(shù)據(jù)
void SLModity(SL* ps, size_t pos, SLDataType x) {
//判斷要修改的位置是否在size之內(nèi)
assert(pos >= 0 && pos < ps->size);
ps->p[pos] = x;
}
同樣的,我自己寫(xiě)的一些小測(cè)試也在Gitee上,需要的小伙伴可以去看看
到此這篇關(guān)于C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組模擬實(shí)現(xiàn)順序表流程詳解的文章就介紹到這了,更多相關(guān)數(shù)組模擬實(shí)現(xiàn)順序表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言 實(shí)現(xiàn)遍歷一個(gè)文件夾的所有文件
這篇文章主要介紹了C語(yǔ)言 實(shí)現(xiàn)遍歷一個(gè)文件夾的所有文件的相關(guān)資料,需要的朋友可以參考下2017-01-01
C語(yǔ)言動(dòng)態(tài)數(shù)組的使用實(shí)現(xiàn)代碼
這篇文章主要介紹了C語(yǔ)言動(dòng)態(tài)數(shù)組的使用實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-01-01
C語(yǔ)言入門(mén)篇--初識(shí)結(jié)構(gòu)體
本篇文章是基礎(chǔ)篇,適合c語(yǔ)言剛?cè)腴T(mén)的朋友,本文對(duì)c語(yǔ)言的結(jié)構(gòu)體做了簡(jiǎn)單的分析,幫助大家快速入門(mén)c語(yǔ)言的世界,更好的理解c語(yǔ)言2021-08-08
詳解C語(yǔ)言解決經(jīng)典問(wèn)題之兔子產(chǎn)子
有一對(duì)兔子,從出生后的第 3 個(gè)月起每個(gè)月都生一對(duì)兔子。小兔子長(zhǎng)到第 3 個(gè)月后每個(gè)月又生一對(duì)兔子,假設(shè)所有的兔子都不死,問(wèn) 30 個(gè)月內(nèi)每個(gè)月的兔子總數(shù)為多少?本文將用C語(yǔ)言解決這一經(jīng)典問(wèn)題,需要的可以參考一下2022-03-03
C語(yǔ)言實(shí)現(xiàn)掃雷小游戲(擴(kuò)展版)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)擴(kuò)展版的掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05

