日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

线性表的定义和基本运算之线性结构

發(fā)布時(shí)間:2025/3/15 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线性表的定义和基本运算之线性结构 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、線性表的邏輯定義和性質(zhì)

線性表是最簡(jiǎn)單和最常用的一種數(shù)據(jù)結(jié)構(gòu),他是由n個(gè)數(shù)據(jù)元素(結(jié)點(diǎn))a1,a2,a3,a4........an組成的有限序列。其中,數(shù)據(jù)元素個(gè)數(shù)那位表的長(zhǎng)度。當(dāng)n為0時(shí)稱為空表,非空的線性表通常記為 (a1,a2,a3,a4........ai-1,ai,..........an)

這里的元素ai(0<?i < n+1)?是一個(gè)抽象的符合,他可以是一個(gè)數(shù)或者一個(gè)符合,還可以是較復(fù)雜的記錄。

從線性表的定義可以看出呀的邏輯特征,對(duì)于一個(gè)非空的線性表:

(1)有且僅有一個(gè)稱為開始元素的a1,它沒有前驅(qū),僅有一個(gè)直接的后繼a2

(2)有且僅有一個(gè)稱為終端元素的an,它沒有后繼,僅有一個(gè)直接前驅(qū)an-1

(3)其余元素ai(1< i <n)稱為內(nèi)部元素,他們都有且僅有一個(gè)直接前驅(qū)ai-1和一個(gè)直接后繼ai+1

二、線性表上的定義和基本運(yùn)算

(1)對(duì)于線性表InitList(L),構(gòu)造一個(gè)空的線性表L

(2)求表長(zhǎng)ListLength(L),返回線性表L中元素的個(gè)數(shù),即表長(zhǎng)

(3)取表中第i個(gè)元素GetNode(L,i),若 0<i<ListLength(L)+1,則返回第i個(gè)元素ai

(4)按值查找LocateNode(L,x),在表L中查找第一個(gè)值為x的元素,并返回該元素在表L中的位置,若表中沒有元素的值為x,則返回0值

(5)插入?InsertList(L,i,x),在表L的第i個(gè)元素之前插入一個(gè)值為x的新元素,表L的長(zhǎng)度加1

(6)刪除?DeleteList(L,i),刪除表L的第i個(gè)元素,表L的長(zhǎng)度減1

?

二、線性表的兩種實(shí)現(xiàn)方式

1.1順序表示(順序表)

概念:用一組地址連續(xù)的存儲(chǔ)單元依次存儲(chǔ)線性表的數(shù)據(jù)元素,這種存儲(chǔ)結(jié)構(gòu)的線性表稱為順序表。

特點(diǎn):邏輯上相鄰的數(shù)據(jù)元素,物理次序也是相鄰的。

??只要確定好了存儲(chǔ)線性表的起始位置,線性表中任一數(shù)據(jù)元素都可以隨機(jī)存取,所以線性表的順序存儲(chǔ)結(jié)構(gòu)是一種隨機(jī)存取的儲(chǔ)存結(jié)構(gòu),因?yàn)楦呒?jí)語(yǔ)言中的數(shù)組類型也是有隨機(jī)存取的特性,所以通常我們都使用數(shù)組來(lái)描述數(shù)據(jù)結(jié)構(gòu)中的順序儲(chǔ)存結(jié)構(gòu),用動(dòng)態(tài)分配的一維數(shù)組表示線性表。

1.2 代碼實(shí)現(xiàn)

以最簡(jiǎn)單的學(xué)生信息管理為例:

首先先創(chuàng)建兩個(gè)數(shù)據(jù)結(jié)構(gòu),如下:

#define maxsize 100 //定義學(xué)生最大數(shù)量 #define OK 1 ??????//正確標(biāo)志 #define ERROR 0?????//失敗標(biāo)志 //學(xué)生信息的數(shù)據(jù)結(jié)構(gòu) typedef struct{int id;???//學(xué)生idchar name[30];???//學(xué)生姓名??? }Student;//順序表數(shù)據(jù)結(jié)構(gòu) typedef struct{Student *elem;???//儲(chǔ)存空間的基地址int length;??????//數(shù)據(jù)結(jié)構(gòu)的長(zhǎng)度 }SqList;//定義SqList類型的變量 SqList L;

這是一個(gè)十分簡(jiǎn)單的例子,這樣我們就可以通過L.elem[i-1]訪問序號(hào)為i的學(xué)生信息了。其實(shí)這里我們用到了指針數(shù)組。如果你對(duì)指針數(shù)組還不熟悉的話,可以去另一篇文章看看:https://blog.csdn.net/qq_38378384/article/details/79951651

1.初始化

基本算法:

//初始化順序表基本算法Status InitList(SqList &L){//構(gòu)造一個(gè)空的順序表LL.elem = new ElemType[maxsize]; //分配內(nèi)存空間if(!L.elem) exit(-1);L.length = 0;return OK;}

2.取值

基本算法:

//順序表取值Status Get(SqList &L,int i,ElemType &e) {if(i<1||i>L.length) return ERROR;e = L.elem[i-1];return OK; }

3.查找

基本算法:

//順序表查找int Find(SqList L,ElemType e) {//查找值為e的數(shù)據(jù)元素,返回其序號(hào)for(i=0;i<L.length;i++){if(L.elem[i]==e) return i+1;}return ERROR; //查找失敗 }

4.插入

基本算法:

//順序表插入Status ListInsert(SqList &L,int i,ElemType e){if((i<1)||(i>L.length+1)) return ERROR; //i不合法if(L.length == maxsize) return ERROR; //滿了for(j=L.length-1;j>=i-1;j--)L.elem[j+1]=L.elem[j]; //將第n個(gè)至i個(gè)位置的元素后移L.elem[i-1]=e; //將e放進(jìn)第i個(gè)位置}

5.刪除

基本算法:

?//順序表刪除Status ListDelete(SqList &L,int i){//刪除第i個(gè)元素,i的值為[1,L.length]if((i<1)||(i>L.length)) return ERROR;for(j=i;j<=L.length-1;j++)L.elem[j-1]=L.elem[j];--L.length; ?//長(zhǎng)度減一return OK;}

算法都十分的簡(jiǎn)單,眼尖的你可能發(fā)現(xiàn)了,為啥有的參數(shù)用的是引用,有的不是呢?

這里我就得講下使用引用作為形參的作用了,主要有三點(diǎn):

(1)使用引用作為參數(shù)與使用指針作為參數(shù)的效果是一樣的,形參變化時(shí)實(shí)參對(duì)應(yīng)也會(huì)變化,這個(gè)我在上篇文章(我上面給的鏈接)也有說(shuō)明,引用只是一個(gè)別名。

(2)引用類型作為形參,在內(nèi)存中并沒有產(chǎn)生實(shí)參的副本,而使用一般變量作為形參,,形參和實(shí)參會(huì)分別占用不同給的存儲(chǔ)空間,當(dāng)數(shù)據(jù)量較大時(shí),使用變量作為形參可能會(huì)浪費(fèi)時(shí)間和空間。

(3)雖然使用指針也可以達(dá)到引用一樣的效果,但是在被調(diào)函數(shù)中需要重復(fù)使用"*指針變量名"來(lái)訪問,很容易產(chǎn)生錯(cuò)誤并且使程序的閱讀性變差。

此時(shí)你會(huì)發(fā)現(xiàn),使用順序表作為存儲(chǔ)時(shí),空間是一次性直接開辟的,所以可能會(huì)有空間不足或者浪費(fèi)空間的情況出現(xiàn),那么為啥不用一個(gè)就分配一個(gè)空間呢,再使用一個(gè)方式將這些空間串起來(lái)不就好了,是時(shí)候展現(xiàn)真正的技術(shù)了(鏈表)。

2.1鏈表

概念:用一組任意的存儲(chǔ)單元存儲(chǔ)線性表的數(shù)據(jù)元素(這組存儲(chǔ)單元可以是連續(xù)的,也可以是不連續(xù)的),包括數(shù)據(jù)域和指針域,數(shù)據(jù)域存數(shù)據(jù),指針域指示其后繼的信息。

這里重點(diǎn)講單鏈表,如圖:

2.1代碼實(shí)現(xiàn)

//單鏈表存儲(chǔ)結(jié)構(gòu)typedef struct LNode{ElemType data; //數(shù)據(jù)域struct LNode *next; //指針域}LNode,*LinkList;

為了提高程序的可閱讀性,在此對(duì)同一結(jié)構(gòu)體指針類型起了兩個(gè)名稱,LinkList與LNode*,本質(zhì)上兩者是等價(jià)的。通常習(xí)慣上用LinkList定義單鏈表,強(qiáng)調(diào)定義的是某個(gè)單鏈表的頭指針,用LNode *定義指向單鏈表中任意結(jié)點(diǎn)的指針變量。

例如,定義LinkList L,則L為單鏈表的頭指針,若定義LNode *p ,則p為指向單鏈表中某個(gè)結(jié)點(diǎn)的指針,用*p代表該結(jié)點(diǎn)。

1.初始化

基本算法:

//初始化?Status InitList(LinkList &L){//構(gòu)造一個(gè)單鏈表L=new LNode; ?//生成頭結(jié)點(diǎn),用頭指針L指向頭結(jié)點(diǎn)L->next =NULL; ?return OK;? ? ?}


2.取值

基本算法:

//取值Status Get(LinkList L,int i,ElemType &e)?{//在帶頭結(jié)點(diǎn)的單鏈表L中根據(jù)序號(hào)I獲取元素的值,用e返回L中第i個(gè)數(shù)據(jù)元素的值p=L->next;j=1;//計(jì)數(shù)器while(p&&j<i) ? ? {??//順著鏈表向后掃描,直到j(luò)==ip=p->next;++j;}if(!p||j>i) return ERROR; //不合法e=p->data; ? //找到該結(jié)點(diǎn)后獲取該結(jié)點(diǎn)的數(shù)據(jù)域return OK;?}


3.查找

基本算法:

//查找LNode *Find(LinkList L,ElemType e)?{p=L->next; //使p指向首元結(jié)點(diǎn)while(p && p->data!=e){p=p->next; ?//不符合條件就一直滾下去}return p; ? //這里有兩種情況,找到的時(shí)候返回指針p,如果找不到那么這個(gè)p則為null,因?yàn)樽詈笠粋€(gè)指向的是null}


?

4.插入

基本算法:

//插入 Status ListInsert(LinkList &L,int i,ElemType e){//在帶頭結(jié)點(diǎn)的單鏈表L中第i個(gè)位置插入值為e的新結(jié)點(diǎn)p=L;j=0;while(p&&(j<i-1)){p=p->next; ? ? ? ? //查找第i-1個(gè)結(jié)點(diǎn),p指向該結(jié)點(diǎn)++j;}if(!p||j>i-1) return ERROR;s=new LNode; ? //生成一個(gè)新結(jié)點(diǎn)s->data=e; ? //將結(jié)點(diǎn)*s的數(shù)據(jù)域置為es->next=p->next; //先接尾部p->next=s; ?//再接頭部 }


?

5.刪除

基本算法:

//刪除 Status ListDelete(LinkList &L,int i){//刪除第i個(gè)元素p=L;j=0;while((p->next)&&(j<i-1)){p=p->next; ? ?//查找i-1個(gè)結(jié)點(diǎn)++j;}if(!(p->next)||(j>i-1)) return ERROR; ?//當(dāng)i>n或i<1時(shí),不符合條件q=p->next; ? //臨時(shí)保存被刪除的地址p->next=q->next; ?//將前驅(qū)結(jié)點(diǎn)指向后驅(qū)delete q; ?//釋放刪除結(jié)點(diǎn)的空間return OK; }

?

其實(shí)單鏈表可以想象成一列人在玩游戲,每個(gè)人都把手搭到后面那個(gè)人的肩膀上,每個(gè)人身上都有一個(gè)大口袋用來(lái)放數(shù)據(jù),最后一個(gè)人沒人可以搭就一直懸空著,第一個(gè)帶頭領(lǐng)隊(duì)的就不用口袋了,它是一個(gè)頭結(jié)點(diǎn),是用來(lái)找到第一個(gè)有口袋的人的,也就是首元結(jié)點(diǎn)。

??這樣想的話就簡(jiǎn)單了,初始化的時(shí)候就是用一個(gè)人當(dāng)頭結(jié)點(diǎn),它沒有口袋,他的手是用來(lái)搭到第一個(gè)有口袋的人肩膀的,因?yàn)檫@個(gè)人還沒來(lái),所以它的next是Null,而取值時(shí),通過參數(shù)i,我們就可以從首元結(jié)點(diǎn)開始數(shù),數(shù)到第i個(gè)人,找到他后,就可以拿他口袋里面的東西,查找是知道口袋里面東西是什么,想找到這個(gè)東西的擁有者,也是一樣從首元結(jié)點(diǎn)開始找。遍歷下去,插入的話,比如要插入第i個(gè)位置,那么我們就先找到第i-1個(gè)人,然后讓新來(lái)的手搭到第i個(gè)人身上,然后再讓第i-1個(gè)人把之前放在第i個(gè)人的手挪開,放在新來(lái)的人的肩膀上,刪除操作的話,例如刪除第i個(gè)人,那么也是先找到第i-1個(gè)人,這里的重點(diǎn)是,因?yàn)殒湵淼牟樵冎荒苁菑念^開始找的,是不能逆回去的,所以我們需要找個(gè)變量把要?jiǎng)h的那個(gè)人的地址先存起來(lái),然后把第i-1個(gè)的手放到第i+1個(gè)人身上,如果我們不找個(gè)變量把那個(gè)人的地址存起來(lái),這時(shí)候我們就沒辦法找到他了,因?yàn)槲覀冇靡粋€(gè)變量臨時(shí)保存他的地址,于是我們只需要釋放這個(gè)地址的空間就可以了。

這就是單鏈表的基本操作,那么如何創(chuàng)建單鏈表呢?

主要有著兩種方法(前插法和后插法)

//前插法創(chuàng)建單鏈表

?void CreateList(LinkList &L,int n)?{//逆次序輸出n個(gè)元素的值L=new LNode;L->next=NULL;for(i=0;i<n;++i)?{p=new LNode; ?//生成新結(jié)點(diǎn)cin>>p->data; ?//輸入新結(jié)點(diǎn)的數(shù)據(jù)域內(nèi)容p->next=L->next; //將新結(jié)點(diǎn)插到頭結(jié)點(diǎn)之后L->next=p;}}


?//后插法

void CreateList(LinkList &L,int n){//正次序輸入n個(gè)元素的值L=new LNode;L->next=NULL; ?//建立一個(gè)帶頭結(jié)點(diǎn)的空鏈表r=L; ? //尾指針r指向頭結(jié)點(diǎn)for(i=0;i<n;++i)?{p=new LNode; //生成新結(jié)點(diǎn)cin>>p->data; //輸入新結(jié)點(diǎn)的數(shù)據(jù)域內(nèi)容p->next=NULL;r->next=p; ?//將新結(jié)點(diǎn)插入尾結(jié)點(diǎn)之后r=p; ? //改變尾指針,使其指向新的尾結(jié)點(diǎn)}}


??兩種方式的結(jié)果是一樣的,區(qū)別就是前插法是把新的元素插到最前面,代替了首元結(jié)點(diǎn)的位置,就是明擺的插隊(duì),而后插法是插到最后面,有點(diǎn)類似于隊(duì)列。而且后插法多了一個(gè)用來(lái)指向尾結(jié)點(diǎn)的尾指針。

?實(shí)際上鏈表還有兩種,雙向鏈表和循環(huán)鏈表,循環(huán)鏈表用的比較多,就是把頭和尾連起來(lái)了,像一個(gè)圈一樣。這里我就不說(shuō)明了,因?yàn)橹灰藛捂湵?#xff0c;另外兩種理解起來(lái)是十分容易的事情。
?

?

?

?

?

?

?

?

?

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的线性表的定义和基本运算之线性结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。