一、前言
最近在重新學習數據結構啦,網上說這本書挺不錯噠,於是我開始啃這本書咯...有一說一,嚴奶奶的書挺好的,就是有點大量使用指針。。。需要沉下心來,看一看畫一畫才能懂,我自己手敲了一遍書上代碼,加上了自己的理解,希望大家也能更清楚的看明白~
好啦廢話不多說,下面就上代碼!
二、代碼
嚴奶奶的書中預定義了一些預定義常量和類型,大家可以 新建一個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;
}