《數據結構(C語言版)》嚴蔚敏代碼實現———順序表


一、前言

最近在重新學習數據結構啦,網上說這本書挺不錯噠,於是我開始啃這本書咯...有一說一,嚴奶奶的書挺好的,就是有點大量使用指針。。。需要沉下心來,看一看畫一畫才能懂,我自己手敲了一遍書上代碼,加上了自己的理解,希望大家也能更清楚的看明白~

好啦廢話不多說,下面就上代碼!

二、代碼

嚴奶奶的書中預定義了一些預定義常量和類型,大家可以 新建一個y.h文件粘貼以下內容, 然后再去復制代碼哦。

y.h文件內容:

/**
 * 嚴奶奶書中的預定義常量和類型
 **/
//函數結果狀態代碼
#define TRUE 1          //成功
#define FALSE 0         //失敗
#define OK 1            //成功
#define ERROR 0         //錯誤
#define INFEASIBLE -1   //不可實行
#define OVERFLOW -2     //溢出
//Status 是函數的類型,其值是函數結果狀態代碼
typedef int Status;

順序表SqList.cpp:

#include "y.h"
#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
typedef int ElemType;
/**
 * 嚴奶奶順序表的實現
 *  by 熊子q 2021.1.28
 **/
#define LIST_INIT_SIZE  100  //線性表存儲空間的初始分配量
#define LISTINCREMENT   10   //線性表存儲空間的分配增量
//強悍如斯的嚴奶奶,強悍如斯的順序表
typedef struct {
    ElemType *elem;          //存儲空間基址
    int length;              //當前長度
    int listsize;            //當前分配的存儲容量(以sizeof(ElemType)為單位)
}SqList;

//順序表初始化
Status InitList_Sq(SqList &L){
    //構造一個空的線性表L,動態分配空間
    L.elem = (ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
    if(!L.elem) exit(OVERFLOW);     //存儲空間分配失敗
    L.length = 0;                   //空表長度為0
    L.listsize = LIST_INIT_SIZE;    //初始存儲容量
    return OK;
}

//銷毀線性表,基本操作,書上沒有,自己寫的
void DestoryList_Sq(SqList &L){
    free(L.elem);
    //釋放后的無效指針必須置為空,不然會導致內存泄漏
    L.elem = NULL;
    L.length=0;
    L.listsize=0;
}

//清空線性表,基本操作,書上沒有,自己寫的
void ClearList_Sq(SqList &L){
    L.length = 0;
}

//判斷線性表是否為空,基本操作,書上沒有,自己寫的
Status ListEmpty_Sq(SqList L){
    if(L.length == 0) return TRUE;
    else return FALSE;
}

//獲取順序表的長度,基本操作,書上沒有,自己寫的
int ListLength_Sq(SqList L){
    return L.length;
}

//獲取元素,基本操作,書上沒有,自己寫的
Status GetElem_Sq(SqList L, int i, ElemType &e){
    //獲取順序表L中第i個位置的元素e
    //i的合法值為1<=i<=ListLength_Sq(L)
    if(i<1 || i>ListLength_Sq(L)) return ERROR;
    e = L.elem[i-1];
    return OK;
}

//獲取前驅元素,基本操作,書上沒有,自己寫的
Status PriorElem_Sq(SqList L, ElemType cur_e, ElemType &pre_e){
    //獲取順序表L中元素值為cur_e的前驅元素next_e
    //成功返回OK,pre_e為前驅,失敗返回FALSE,pre_e為隨機值
    //雙指針p,pre操作;p為遍歷元素的指針,pre指針永遠指向p指針的前一個地址,即pre_e
    ElemType *pre;
    for(ElemType *p = L.elem;p<=&(L.elem[L.length-1]);p++){
        if(*p == cur_e){
            pre_e = *pre;
            return OK;
        }
        pre=p;
    }
    return FALSE;
}

//獲取后繼元素,基本操作,書上沒有,自己寫的
Status NextElem_Sq(SqList L, ElemType cur_e, ElemType &next_e){
    //獲取順序表L中元素值為cur_e的后繼元素next_e
    //成功返回OK,next_e為后繼,失敗返回FALSE,next_e為隨機值
    //雙指針p,nxt操作;p為遍歷元素的指針,nxt指針永遠指向p指針的后一個地址,即next_e
    ElemType *nxt = L.elem+1;
    for(ElemType *p = L.elem;p<&(L.elem[L.length-1]);p++,nxt++){
        if(*p == cur_e){
            next_e = *nxt;
            return OK;
        }
    }
    return FALSE;
}

//順序表插入,時間復雜度為O(n)
Status ListInsert_Sq(SqList &L, int i, ElemType e){
    //在順序表L中第i個位置之前插入新的元素e
    //i的合法值為1<=i<=ListLength_Sq(L)+1
    if(i<1||i>ListLength_Sq(L)+1) return ERROR;     //i值不合法
    if(L.length >= L.listsize){                     //當前存儲空間已滿,增加分配
        ElemType *newbase = (ElemType*)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof(ElemType));
        if(!newbase) exit(OVERFLOW);                //存儲分配失敗
        L.elem = newbase;                           //新基址
        L.listsize += LISTINCREMENT;                //增加存儲容量
    }
    ElemType *q = &(L.elem[i-1]);                   //q為插入位置
    //插入位置及之后的元素右移
    for(ElemType *p = &(L.elem[L.length-1]);p>=q;--p)
        *(p+1) = *p;
    *q = e;                                         //插入e
    ++L.length;                                     //表長增1
    return OK;
}

//順序表刪除,時間復雜度為O(n)
Status ListDelete_Sq(SqList &L, int i, ElemType &e){
    //在順序表L中刪除第i個元素,並用e返回其值
    //i的合法值為1<=i<=ListLength_Sq(L)
    if(i<1 || i>ListLength_Sq(L)) return ERROR;   //i值不合法
    ElemType *p = &(L.elem[i-1]);           //p為被刪除元素的位置
    e = *p;                                 //被刪除元素的值賦給e
    ElemType *q = L.elem + L.length - 1;    //表尾元素的位置
    for(++p;p<=q;++p) *(p-1) = *p;          //被刪除元素之后的元素左移
    --L.length;
    return OK;
}

//順序表的查找
int LocateElem_Sq(SqList L, ElemType e, Status(*compare)(ElemType, ElemType)){
    //在順序表L中查找第1個值與e滿足compare()的元素的位序
    //若找到,則返回其在L中的位序,否則返回0
    //第三個參數是一個函數指針,該函數的必須符合以下2點要求:
    //1.返回值為Status。2.有兩個參數,且類型為ElemType
    int i = 1;              //位序i的初值為1
    ElemType *p = L.elem;   //p的初值為第一個元素的存儲位置
    //遍歷順序表
    while(i <= L.length && !(*compare)(*p++ ,e)) ++i;
    if(i <= L.length) return i;
    else return 0;
}

//順序表的合並,時間復雜度為O(La.length+Lb.length)
void MergeList_Sq(SqList La, SqList Lb, SqList &Lc){
    //已知順序表La和Lb的元素按值非遞減排列(遞增排列)
    //歸並La和Lb得到新的順序表Lc,Lc的元素也按值非遞減排列(遞增排列)
    //pa和pb指針是遍歷La和Lb每一個元素的指針,pc指針永遠指向Lc的待插入元素位置
    ElemType *pa = La.elem,*pb = Lb.elem;
    Lc.listsize = Lc.length = La.length + Lb.length;
    ElemType *pc = Lc.elem = (ElemType*)malloc(Lc.listsize*sizeof(ElemType));
    if(!Lc.elem) exit(OVERFLOW);                    //存儲分配失敗
    //pa_last和pb_last指針是指向La和Lb最后一個元素的指針,pa<=pa_last即遍歷La中每一個元素,Lb同理
    ElemType* pa_last = La.elem + La.length - 1;
    ElemType* pb_last = Lb.elem + Lb.length - 1;
    while(pa <= pa_last && pb <= pb_last){          //歸並
        /**
         * 判斷pa和pb所指向的元素誰大,取其中較小的數添加到Lc中,然后兩個指針后移 
         * *pc++ =*pa++;相當於以下三條語句:
         * *pc = *pa;   //將pa所指向的元素值賦值給pc所指向的元素值
         * pc++;pa++;   //pc和pa指針后移
         **/ 
        if(*pa <= *pb) *pc++ =*pa++;
        else *pc++ = *pb++;
    }
    //以下兩個while只會進入一個,因為上個while遍歷的結束條件就是La或Lb遍歷完畢
    while(pa <= pa_last) *pc++ = *pa++;             //插入La的剩余元素
    while(pb <= pb_last) *pc++ = *pb++;             //插入Lb的剩余元素
}

//順序表的輸出
void Display_Sq(SqList L){
    printf("馬上就輸出這個叫L的線性表啦~\n");
    printf("順序表的內容:");
    for(int i=0;i<ListLength_Sq(L);i++){
        if(i!=0) printf(" ");
        printf("%d",L.elem[i]);
    }
    printf("\n");
}

Status cmp(ElemType a,ElemType b){
    if(a>b) return OK;
    else return FALSE;
}

int main(){
    
    SqList L;
    InitList_Sq(L);                 //初始化線性表
    int a[5] = {4,2,1,3,5};
    for(int i=0;i<5;i++){           //插入元素到線性表L
        ListInsert_Sq(L,i+1,a[i]);
    }
    Display_Sq(L);                  //輸出線性表
    printf("線性表為空?%s\n\n",
        ListEmpty_Sq(L)==TRUE?"TRUE":"FALSE");//判斷線性表是否為空
    printf("順序表的長度:%d\n\n",
        ListLength_Sq(L));          //輸出線性表長度
    int tmp;                        //臨時變量,方便下面方法使用
    GetElem_Sq(L,2,tmp);            //獲取指定元素
    printf("第2個元素是:%d\n\n",tmp);
    PriorElem_Sq(L,5,tmp);          //獲取前驅
    printf("5的前驅元素為:%d\n\n",tmp);        
    NextElem_Sq(L,2,tmp);           //獲取后繼
    printf("2的后繼元素為:%d\n\n",tmp);
    ListDelete_Sq(L,3,tmp);         //刪除元素
    printf("刪除第3個元素后:\n");
    Display_Sq(L);
    tmp = LocateElem_Sq(L,3,cmp);   //查找第1個值與e滿足cmp的元素的位序
    printf("\n第一個比3小的元素下標為:%d\n\n",tmp);
    printf("清空線性表咯~\n");        //清空線性表
    ClearList_Sq(L);
    Display_Sq(L);
    DestoryList_Sq(L);              //刪除線性表
    return 0;
}

三、運行截圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM