棧:棧是隻能在表的一端(表尾)進行 插入和刪除的線性表;容許插入及刪除的一端(表尾)稱爲棧頂(Top); . 另外一端(表頭)稱爲棧底(Bottom);當表中沒有元素時稱爲空棧node
進棧:在棧頂插入一元素; 數組
出棧:在棧頂刪除一元素;函數
棧的特色:後進先出,棧中元素按a1,a2,a3,…an的次序進棧,出棧的第一個元素應 爲棧頂元素。換句話說,棧的修改是按後進先出的原則進行的。 所以,棧稱爲後進先出線性表(LIFO)。spa
棧的用途:經常使用於暫時保存有待處理的數據3d
約定棧的第1個元素存在data[1]中, 則: s->top==0 表明順序棧s爲空; s->top==maxsize-1 表明順序棧s爲滿 ;指針
//棧大小 const int maxsize=6; //一、順序棧類型的定義 typedef struct seqstack { DataType data[maxsize]; int top; }SeqStk; //二、棧的初始化 int Initstack(SeqStk *stk){ stk->top=0; return 1; } //三、判斷空棧(棧空時返回值爲1,不然返回值爲0) int EmptyStack(SeqStk *stk){ if(stk->top= =0){ return 1; }else{ else return 0; } } /*四、進棧 數據元素x進順序棧sq*/ int Push(SeqStk *stk, DataType x){ /*判是否上溢*/ if(stk->top==maxsize -1){ error(「棧滿」);return 0; } else { stk->top++;/*修改棧頂指針,指向新棧頂*/ stk->data[stk->top]=x; /*元素x插入新棧頂中*/ return 1; } } /*五、出棧 順序棧sq的棧頂元素退棧*/ int Pop(SeqStk *stk){ /*判是否下溢*/ if(stk->top==0){ error(「棧空」); return 0; }else { stk->top-- ; /*修改棧頂指針,指向新棧頂*/ return 1; } } //六、 取棧頂元素 DataType GetTop(SeqStk *stk){ if(EmptyStack(stk)){ return NULLData; }else{ return stk->data[stk->top]; } }
棧的鏈式存儲結構稱爲鏈棧,它是運算受限的單鏈表, 插入和刪除操做僅限制在表頭位置上進行。棧頂指針就是鏈 表的頭指針code
下溢條件:LS->next==NULL;上溢:鏈棧不考慮棧滿現象blog
//一、鏈棧的定義 typedef struct node{ DataType data; struct node *next } LkStk; //二、鏈棧的初始化 void InitStack(LkStk *LS){ LS=(LkStk *)malloc(sizeof(LkStk)); LS->next=NULL; } //三、判斷棧空 int EmptyStack(LkStk *LS){ if(LS->next= =NULL){ return 1; } else{ return 0; } } //四、進棧:在棧頂插入一元素x:生成新結點(鏈棧不會有上溢狀況發生);將新結點插入鏈棧中並使之成爲新的棧頂結點 void Push (LkStk *LS, DataType x){ LkStk *temp; temp= (LkStk *) malloc (sizeof (LkStk)); temp->data=x; temp->next=LS->next; LS->next=temp; } //五、出棧:在棧頂刪除一元素,並返回;考慮下溢問題;不下溢,則取出棧頂元素,從鏈棧中刪除棧頂結點並將結點回歸系統 int Pop (LkStk *LS){ LkStk *temp; if (!EmptyStack (LS)){ temp=LS->next; LS->next=temp->next; free(temp); return 1; }else{ return 0; } } //六、取棧頂元素 DataType GetTop(LkStk *LS){ if (!EmptyStack(LS)){ return LS->next->data; }else{ return NULLData; } }
隊列(Queue)也是一種運算受限的線性表。隊列
隊列:是隻容許在表的一端進行插入,而在另外一 端進行刪除的線性表。內存
其中:容許刪除的一端稱爲隊頭(front), 容許插入的另外一端稱爲隊尾(rear)。 隊列 Q=(a1,a2,a3,…an )
隊列特色:先進先出(FIFO);經常使用於暫時保存有待處理的數據
一、隊列的順序實現
隊列的順序實現:通常用一維數組做爲隊列的存儲結構
隊列容量:隊列中可存放的最大元素個數
初始: front=rear=0
進隊: rear增1,元素插入尾指針所指位置
出隊: front增1,取頭指針所指位置元素
隊頭指針front:始終指向實際隊頭元素的前一位置
隊尾指針 rear:始終指向實際隊尾元素
//順序隊列的構造 const int maxsize=20; typedef struct seqqueue { DataType data[maxsize]; int front, rear ; }SeqQue; SeqQue sq;
入隊列操做:sq.rear=sq.rear+1;sq.data[sq.rear]=x;
出隊列操做:sq.front=sq.front+1;
上溢條件:sq.rear = = maxsize-1 ( 隊滿 )
下溢條件:sq.rear = = sq.front (隊列空)
順序隊列的假溢出:sq.rear == maxsize-1,但隊列中實際容量並未達到最大容量的現象;極端現象:隊列中的項很少於1,也致使「上溢」.假溢出浪費空間循環隊列能夠解決該問題
二、循環隊列
爲隊列分配一塊存儲空間(數組表示),並將 這一塊存儲空間當作頭尾相鏈接的。
下溢條件即隊列空: CQ.front==CQ.rear
上溢條件即隊列滿: 尾指針從後面追上頭指針;即:(CQ.rear+1)%maxsize==CQ.front (浪費一個空間,隊滿時實際隊容量=maxsize-1)
//循環隊列的定義 typedef struct Cycqueue{ DataType data[maxsize]; int front,reat; }CycQue; CycQue CQ; //循環隊列的初始化 void InitQueue(CycQue CQ){ CQ.front=0; CQ.rear=0; } //循環隊列判斷空 int EmptyQueue(CycQue CQ){ if (CQ.rear==CQ.front){ return 1; } else{ else return 0; } } 入隊——在隊尾插入一新元素x ● 判上溢否?是,則上溢返回; ● 不然修改隊尾指針(增1),新元素x插入隊尾。 int EnQueue(CycQue CQ,DataType x){ if ((CQ.rear+1)%maxsize==CQ.front){ error(「隊列滿」);return 0; }else { CQ.rear=(CQ.rear+1)%maxsize; CQ.data[CQ.rear]=x; return 1; } } 出隊——刪除隊頭元素,並返回 ● 判下溢否?是,則下溢返回; ● 不下溢,則修改隊頭指針,取隊頭元素。 int OutQueue(CycQue CQ){ if (EmptyQueue(CQ)){ error(「隊列空」); return 0; }else { CQ.front=(CQ.front+1)%maxsize; return 1; } } //.取隊列首元素 DataType GetHead(CycQue CQ){ if (EmptyQueue(CQ)){ return NULL; }else{ return CQ.data[(CQ.front+1)%maxsize]; } }
三、隊列的連接實現
隊列的連接實現其實是使用一個帶有頭結點的單鏈表來表示隊列,稱爲鏈隊列。頭指針指向鏈表的頭結點,單鏈表的頭結點的next 域指向隊列首結點,尾指針指向隊列尾結點,即單鏈表的最後一個結點
//類型定義 typedef struct LinkQueueNode{ DataType data; struct LinkQueueNode *next; } LkQueNode; typedef struct LkQueue{ LkQueNode *front, *rear; }LkQue; LkQue LQ; 因爲連接實現須要動態申請空間,故鏈隊列在必定範圍內不會出現隊列滿的狀況,當(LQ.front==LQ.rear)成立時,隊列中無數據元素,此時隊列爲空 //(1)隊列的初始化 void InitQueue(LkQue *LQ){ LkQueNode *temp; temp= (LkQueNode *)malloc (sizeof (LkQueNode)); //生成隊列的頭結點 LQ->front=temp; //隊列頭才旨針指向隊列頭結點 LQ->rear=temp; //隊列尾指針指向隊列尾結點 (LQ->front) ->next=NULL; } //判隊列空 int EmptyQueue(LkQue LQ){ if (LQ.rear==LQ.front){ return 1; //隊列爲空 }else{ return 0; } } //入隊列 void EnQueue(LkQue *LQ;DataType x){ LkQueNode *temp; temp=(LkQueNode *)malloc(sizeof(LkQueNode)); temp->data=x; temp->next=NULL; (LQ->rear)->next=temp; //新結點入隊列 LQ->rear=temp; //置新的隊列尾結點 } //出隊列 OutQueue(LkQue *LQ){ LkQueNode *temp; if (EmptyQueue(CQ)){ //判隊列是否爲空 error(「隊空」); //隊列爲空 return 0; }else { //隊列非空 temp=(LQ->front) ->next; //使 temp 指向隊列的首結點 (LQ->front) ->next=temp->next; //修改頭結點的指針域指向新的首結點 if (temp->next==NULL){ LQ->rear=LQ->front; //無首結點時,front 和 rear 都指向頭結點 } free(temp); return 1; } } //取隊列首元素 DataType GetHead (LkQue LQ){ LkQueNode *temp; if (EmptyQueue(CQ)){ return NULLData; //判隊列爲空,返回空數據標誌 } else { temp=LQ.front->next; return temp->data; //隊列非空,返回隊列首結點元素 } }
數組:是線性表的推廣,其每一個元素由一個值和一組下標組成,其中下標個數稱爲數組的維數
一維數組:數組能夠當作線性表的一種推廣,一維數組又稱向量,它由一組具備相同類型的數據元素組成,並存儲在一組連續的存儲單元中
多維數組:若一維數組中的數據元素又是一維數組結構,則稱爲二維數組;依此類推,若一維數組中的元素又是一個二維數組結構,則稱做三維數組,通常地,一個 n 維數組能夠當作元素爲 (n-1) 維數組的線性表,多維數組是線性表的推廣
二維數組Amn能夠當作是由m個行向量組成的向量,也能夠當作是n個列向量組成的向量。
數組一旦被定義,它的維數和維界就再也不改變。所以,除告終構的初始化和銷燬以外,數組一般只有兩種基本運算:
數組的存儲結構
一維數組元素的內存單元地址是連續的,二維數組可有兩種存儲方法:一種是以列序爲主序的存儲;另外一種是以行序爲主序的存儲。數組元素的存儲位置是下標的線性函數
1. 存儲結構:順序存儲結構
因爲計算機的內存結構是一維的,所以用一維內存來表示多維數組,就必須按某種次序將數組元素排成一列序列,而後將這個線性序列存放在存儲器中;又因爲對數組通常不作插入和刪除操做,也就是說,數組一旦創建,結構中的元素個數和元素間的關係就再也不發生變化。所以,通常都是採用順序存儲的方法來表示數組。
二、矩陣的壓縮存儲
爲了節省存儲空間, 咱們能夠對這類矩陣進行壓縮存儲:即爲多個相同的非零元素只分配一個存儲空間;對零元素不分配空間。
特殊矩陣:即指非零元素或零元素的分佈有必定規律的矩陣。下面咱們討論幾種特殊矩陣的壓縮存儲。