數據結構導論之第三章(棧、隊列、數組)

棧和隊列可看做是特殊的線性表,它們是運算受限的線性表

1、棧

棧:棧是隻能在表的一端(表尾)進行 插入和刪除的線性表;容許插入及刪除的一端(表尾)稱爲棧頂(Top); . 另外一端(表頭)稱爲棧底(Bottom);當表中沒有元素時稱爲空棧node

進棧:在棧頂插入一元素; 數組

出棧:在棧頂刪除一元素;函數

棧的特色:後進先出,棧中元素按a1,a2,a3,…an的次序進棧,出棧的第一個元素應 爲棧頂元素。換句話說,棧的修改是按後進先出的原則進行的。 所以,棧稱爲後進先出線性表(LIFO)。spa

棧的用途:經常使用於暫時保存有待處理的數據3d

一、棧的順序實現:順序棧

  • ● 棧容量——棧中可存放的最大元素個數;
  • ● 棧頂指針 top——指示當前棧頂元素在棧中的位置;
  • ● 棧空——棧中無元素時,表示棧空;
  • ● 棧滿——數組空間已被佔滿時,稱棧滿;
  • ● 下溢——當棧空時,再要求做出棧運算,則稱「下溢」;
  • ● 上溢——當棧滿時,再要求做進棧運算,則稱「上溢」。

 

 約定棧的第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;
    }
}

 2、隊列

隊列(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; //隊列非空,返回隊列首結點元素
    }
}

3、數組

數組:是線性表的推廣,其每一個元素由一個值和一組下標組成,其中下標個數稱爲數組的維數

一維數組:數組能夠當作線性表的一種推廣,一維數組又稱向量,它由一組具備相同類型的數據元素組成,並存儲在一組連續的存儲單元中

多維數組:若一維數組中的數據元素又是一維數組結構,則稱爲二維數組;依此類推,若一維數組中的元素又是一個二維數組結構,則稱做三維數組,通常地,一個 n 維數組能夠當作元素爲 (n-1) 維數組的線性表,多維數組是線性表的推廣

二維數組Amn能夠當作是由m個行向量組成的向量,也能夠當作是n個列向量組成的向量。

數組一旦被定義,它的維數和維界就再也不改變。所以,除告終構的初始化和銷燬以外,數組一般只有兩種基本運算:

  • 讀:給定一組下標,返回該位置的元素內容;
  • 寫:給定一組下標,修改該位置的元素內容。

數組的存儲結構
一維數組元素的內存單元地址是連續的,二維數組可有兩種存儲方法:一種是以列序爲主序的存儲;另外一種是以行序爲主序的存儲。數組元素的存儲位置是下標的線性函數

1. 存儲結構:順序存儲結構
  因爲計算機的內存結構是一維的,所以用一維內存來表示多維數組,就必須按某種次序將數組元素排成一列序列,而後將這個線性序列存放在存儲器中;又因爲對數組通常不作插入和刪除操做,也就是說,數組一旦創建,結構中的元素個數和元素間的關係就再也不發生變化。所以,通常都是採用順序存儲的方法來表示數組。

 

 

 

 二、矩陣的壓縮存儲

爲了節省存儲空間, 咱們能夠對這類矩陣進行壓縮存儲:即爲多個相同的非零元素只分配一個存儲空間;對零元素不分配空間。

特殊矩陣:即指非零元素或零元素的分佈有必定規律的矩陣。下面咱們討論幾種特殊矩陣的壓縮存儲。

 

 

相關文章
相關標籤/搜索