顺序表
1. 顺序表的定义 (1) 顺序存储方法 即把线性表的结点按逻辑次序依次存放在一组地址连续的存储单元里的方法。 (2) 顺序表(Sequential List) 用顺序存储方法存储的线性表简称为顺序表(Sequential List)。
2. 结点ai 的存储地址 不失一般性,设线性表中所有结点的类型相同,则每个结点所占用存储空间大小亦相同。假设表中每个结点占用c个存储单元,其中第一个单元的存储地址则是该结点的存储地址,并设表中开始结点a1的存储地址(简称为基地址)是LOC(a1),那么结点ai的存储地址LOC(ai)可通过下式计算: LOC(ai)= LOC(a1)+(i-1)*c 1≤i≤n 注意: 在顺序表中,每个结点ai的存储地址是该结点在表中的位置i的线性函数。只要知道基地址和每个结点的大小,就可在相同时间内求出任一结点的存储地址。是一种随机存取结构。
3.顺序表类型定义 #define ListSize 100 //表空间的大小可根据实际需要而定,这里假设为100 typedef int DataType; //DataType的类型可根据实际情况而定,这里假设为int typedef struct { DataType data[ListSize];//向量data用于存放表结点 int length;//当前的表长度 }SeqList; 下面是本人用写的代码:
#pragma once //只编译一次 #define __SEQ_LIST__ #ifdef __SEQ_LIST__
#include<stdio.h> #include<string.h> #include<assert.h>
#define MAX_SIZE 100 typedef int DataType;
typedef struct SeqList //定义这个顺序表的结构体类型 { DataType array[MAX_SIZE]; size_t size; }SeqList;
void InitSeqList(SeqList *pSeq); //初始化 void PrintSeqList(SeqList* pSeq);//打印 void Pushback(SeqList* pSeq,DataType x);//尾插 void Pushfront(SeqList* pSeq,DataType x);//头插 void Popback(SeqList* pSeq);//尾删 void Popfront(SeqList* pSeq);//头删 void Insert(SeqList* pSeq, size_t index, DataType x);//插入 void Modified (SeqList* pSeq, size_t index, DataType x );//修改 void Remove(SeqList* pSeq, size_t index);//移除 int FindRet (SeqList* pSeq, DataType x,int index);//查找下标 void Erase(SeqList* pSeq, DataType x);//删除一个或所有
#endif __SEQ_LIST__ /****************************/ #include"SeqList.h"
void InitSeqList(SeqList *pSeq) { assert(pSeq); memset(pSeq->array ,0,MAX_SIZE*sizeof(DataType));//初始化顺序表 pSeq->size = 0;//将有效元素的个数初始化为0 } void PrintSeqList(SeqList *pSeq) { size_t i = 0; assert(pSeq); for(i = 0;i<pSeq->size ;++i) { printf("%d ",pSeq->array[i]);//依次将顺序表中的内容打印出来 } printf("\n"); } void Pushback(SeqList* pSeq,DataType x) { assert(pSeq); if(pSeq->size >MAX_SIZE-1) //判断顺序表是否已满 { printf("SeqList is full\n"); return ; } else { pSeq->array[pSeq->size++] = x; //在尾部插入数据 } } void Pushfront(SeqList* pSeq,DataType x) { assert(pSeq); if(pSeq->size > MAX_SIZE-1) //判断顺序表是否满 { printf("SeqList is full\n"); return ; } else { int i = pSeq->size ; for(;i> 0;i--) { pSeq->array [i]=pSeq->array[i-1]; //移动数据 } pSeq->array [0] = x;//在头部插入数据 ++pSeq->size; //使有效元素的个数增加 } } void Popback(SeqList* pSeq) { int i = pSeq->size-1; assert(pSeq); if(pSeq->size < 1) { printf("SeqList is empty!\n");//判断顺序表是否已空 return; } else { pSeq->array[pSeq->size -1] = 0;//将最后一个元素置0 --pSeq->size ;//将有效元素的个数减少 } } void Popfront(SeqList* pSeq) { assert(pSeq); if(pSeq->size < 1) { printf("SeqList is empty!\n");//判断顺序表是否已空 return; } else { size_t i = 1; for(;i<pSeq->size ;i++) { pSeq->array[i-1] = pSeq->array[i]; //直接将后一个将前一个覆盖 } --pSeq->size; } } void Insert(SeqList* pSeq, size_t index, DataType x) { size_t i = pSeq->size; assert(pSeq); if(index > pSeq->size) //判断下标是否是顺序表中的 { printf("Not found index!\n"); return ; }
for(; i > index;i--) { pSeq->array[i] = pSeq->array[i-1]; } pSeq->array[index] = x; //插入值 ++pSeq->size; } void Modified (SeqList* pSeq, size_t index, DataType x ) { assert(pSeq); if(index > pSeq->size)//判断下标是否是顺序表中的 { printf("Not found index!\n"); return ; } else { pSeq->array[index] = x;//修改index下标处的元素 } } void Remove(SeqList* pSeq, size_t index)//移除某个下标处的元素 { assert(pSeq); if(index > pSeq->size) //判断下标是否是顺序表中的 { printf("Not found index!\n"); return ; } else { for(index;index <= pSeq->size - 1;index++) { pSeq->array[index] = pSeq->array[index+1];//将index下标以后的元素都依次执行后一个往前一个覆盖 } --pSeq->size ; //有效元素的个数减少 } }
int FindRet(SeqList* pSeq, DataType x,size_t index ) { index = 0; assert(pSeq);
for(;index < pSeq->size;index++ ) { if(x == pSeq->array[index]) //查找某个元素的下标 { return index;//并且返回这个下标下标 } } return -1;//未找到返回-1 } void Erase(SeqList* pSeq, DataType x) { int flag = 0;//定义标志所要删除元素是one;还是all int ret = FindRet(pSeq,x,0);//这里是从第一个元素往后找 assert(pSeq);
if(ret == -1) { printf("Not found the number you want earse!\n"); return ; } else { printf("flag为1->只删除一个X;flag为0->删除所有的X:\n"); scanf("%d",&flag); switch(flag) { case 1: Remove(pSeq,ret); break; case 0: do{ Remove(pSeq, ret); ret = FindRet(pSeq,x,ret); }while(ret != -1);//这是do while循环的执行条件
break; default: break; } } } /****************************/ #include"SeqList.h"
void test1() //定义几个tes函数,为避免主函数的庞大 { SeqList s; //定义了一个结构体s,用来存放顺序表内容 InitSeqList(&s);//将顺序表中的所有元素全部初始化为0 Pushback(&s,1);// Pushback(&s,1); Pushfront(&s,100); Pushfront(&s,123); Popback(&s); Popfront(&s); PrintSeqList(&s); } void test2() { SeqList s; InitSeqList(&s); Insert(&s,0,19); Insert(&s,1,19); Insert(&s,2,19); Insert(&s,3,19); Modified(&s,0,100); Modified(&s,1,100); Modified(&s,2,100); Remove(&s,0); Remove(&s,1); PrintSeqList(&s); } void test3() { SeqList s; InitSeqList(&s); Insert(&s,0,1); Insert(&s,1,2); Insert(&s,2,2); Insert(&s,3,3); Insert(&s,4,4); PrintSeqList(&s); Erase(&s,2); PrintSeqList(&s); }
int main() { test1(); test2(); test3(); return 0; } 这个小型的工程由一个头文件和两个源文件组成,在这里我用(/*************/)分割开每一个文件。
经验总结:
1>.写完每个函数之后就立即测试它的功能,而不是将所有的函数功能模块要写完之后再测试,已避免错误百出。
2>.在编一些逻辑不是那么清晰的语句时,应该尽量用画图使思路更加清晰,而不是空想。
3>.当程序已经能满足我们的需求时,我们应该尽量把程序优化。
|