线性数据结构
线性数据结构是包含n个相同性质数据元素的有限序列。
特点:两点确定一条直线,存在的唯一两点——即第一个元素和最后一个元素,其他数据元素均有唯一的“直接后继”和“直接前继”数组是存储多个相同类型的数据的集合。
常见线性数据结构的典型例子有栈、队列、线性表等,实现的方式有顺序存储和线性存储
结构 | 特殊位置 | 操作位置 | 基本操作 | 操作方式 |
---|---|---|---|---|
栈 | 栈顶、栈底 | 栈顶 | 出栈、入栈、取栈顶元素 | 先入后出 |
队列 | 队头、队尾 | 队头、队尾 | 入队、出队 | 先入先出 |
线性表 | 任意位置 | 任意位置插入、删除、查询、修改 |
线性结构的存储表示
线性结构的存储表示主要有两种:顺序存储和链式存储。
顺序存储的特点是借助数据元素在存储空间中的相对位置来表示元素之间的逻辑关系。最简单的一种方式是用相邻位置表示逻辑关系,即逻辑相邻的元素在物理上也相邻。
链式存储的特点是借助指示数据元素存储地址的指针表示元素之间的逻辑关系。
如何实现
顺序栈——采用顺序存储结构的栈
下面代码是顺序栈的基本出栈、入栈操作
入栈:Status Push (SqStack &S, ElemType e)
判断内存空间是否已满S.top>=S.size
将e元素压入栈中,并将栈顶位标后移
出栈:Status Pop (SqStack &S, ElemType &e)
判断是否是空栈S.top==0
位标后移,并将指针指向的元素赋值给e
#include <stdio.h>
#include <stdlib.h>
//函数结果状态代码,当函数返回值为函数结果状态代码时,函数定义为Status类型
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;//用作函数值类型,表示函数结构状态
//----- 栈的顺序存储表示 -----
#define STACK_INIT_SIZE 10 // 存储空间的初始分配量
#define STACKINCREMENT 5// 存储空间的分配增量
typedef struct {
ElemType *base;//头指针作为栈顶指针指向栈顶元素节点
int top;//栈顶位标,指向栈顶元素下一个位置
int size;//当前分配的存储容量
int increment; // 扩容时,增加的存储容量
} SqStack;
// 初始化,构造一个空栈 S
Status InitStack(SqStack &S){
S.base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));//分配一个长度为STACK_INIT_SIZE * sizeof(ElemType)的存储空间,并且base指针指向这片空间
if(!S.base) exit (OVERFLOW);//分配失败就退出
S.top = 0;//置S为空栈
S.size = STACK_INIT_SIZE;//初始容量值
S.increment = STACKINCREMENT;//初始增量值
return OK;
}
// 判栈 S 是否为空栈
Status StackEmpty(SqStack S){
if (S.top==0) return TRUE;
else return FALSE;
}
//形参列表中以&打头的代表引用参数,当改变此形参值时,相对应的实参值也会发生改变
//入栈函数
Status Push (SqStack &S, ElemType e) {
ElemType *newbase;//建立新基址
//判断是否内存空间是否已满
if(S.top>=S.size){
newbase=(ElemType *)realloc(S.base,(S.size+S.increment)*sizeof(ElemType));//扩容
if(NULL==newbase)return OVERFLOW;//扩容失败
S.base=newbase;//将base指针指向newbase所指向的位置
S.size+=S.increment;
}
S.base[S.top++]=e;//将e元素放入base指向的空间,并将栈顶位标后移
return OK;
}
//出栈函数
Status Pop (SqStack &S, ElemType &e) {//ElemType &e; 其中e是引用。
if(S.top==0)//判断是否是空栈
{
return ERROR;
}
S.top--;//栈顶位标后移
e=S.base[S.top];//将base指向的元素赋值给e
return OK;
}
//输出顺序栈函数
void OutStack(SqStack S)
{ ElemType e;
if(TRUE == StackEmpty(S)){
printf("这是一个空栈!");
}
else
while(FALSE == StackEmpty(S)){
Pop(S,e);
printf("%6d", e);
}
printf("\n");
}
//主函数
int main()
{ SqStack s;
int cord; ElemType a;
printf("第一次使用必须初始化!\n");
do{
printf("\n 主菜单 \n");
printf(" 1 初始化顺序栈 ");
printf(" 2 插入一个元素 ");
printf(" 3 删除栈顶元素 ");
printf(" 4 结束程序运行 ");
printf("\n-------------------------------------------------------------------\n");
printf("请输入您的选择( 1, 2, 3, 4)");
scanf("%d",&cord);
printf("\n");
switch(cord)
{ case 1:
InitStack(s);
OutStack(s);
break;
case 2:
printf("请输入要插入的数据元素:a=");
scanf("%d",&a);
Push(s,a);
printf("%d 进栈之后的栈:",a);
OutStack(s);
break;
case 3:
Pop(s,a);
printf("栈顶元素 %d 出栈之后的栈:",a);
OutStack(s);
break;
case 4:
exit(0);
}
}while (cord<=4);
}
顺序栈实现进制转换
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
//定义不同的数据类型名称是为了程序的可读性.
//而且一旦你需要将类型变换比如使用double型的了,只要写:
//typedef double ElemType;
//一下子就全改了,如果没有定义的话就要一个个的把int改成double,你不嫌麻烦么
typedef int ElemType;
typedef int Status;
#define STACK_INIT_SIZE 10
#define STACKINCREMENT 5
typedef struct {
ElemType *base;//头指针指向栈顶
int top;//栈顶位标
int size;// 当前分配的存储容量
int increment; // 扩容时,增加的存储容量
} SqStack;//顺序栈
// 构造一个空栈 S:初始化
Status InitStack(SqStack &S){
//base指向这块内存空间
S.base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));//申请一个 长度为STACK_INIT_SIZE * sizeof(ElemType)大小的内存空间
// sizeof(ElemType)表示数据类型elemType在内存中的长度
if(!S.base) exit (OVERFLOW);//申请失败
S.top = 0;//置S为空栈
S.size = STACK_INIT_SIZE;//初始容量值
S.increment = STACKINCREMENT;//初始增量值
return OK;
}
// 判栈 S 是否为空栈
Status StackEmpty(SqStack S){
if (S.top==0) return TRUE;
else return FALSE;
}
//入栈函数
Status Push (SqStack &S, ElemType e) {
//判断栈是否内存已满
ElemType *newbase;
if(S.top>=S.size)
{
newbase=(ElemType *)realloc(S.base,(S.size+S.increment)*sizeof(ElemType));
if(newbase==NULL) return OVERFLOW;
S.base=newbase;
S.size+=S.increment;
}
S.base[S.top++]=e;
return OK;
}
//出栈函数
Status Pop (SqStack &S, ElemType &e) {
if(S.top==0) return ERROR;
S.top--;
e=S.base[S.top];
return OK;
}
//十进制转八进制函数
void conversion()
{ SqStack S;
int n,d;
ElemType e;
printf("请输入一个十进制数");
scanf("%d",&n);
printf("请输入要转换的进制数");
scanf("%d",&d);
InitStack(S);
while(n!=0)
{
Push(S,n%d);
n/=d;
}
while(FALSE== StackEmpty(S))
{
Pop(S,e);
printf("%d",e);
}
}
int main()
{
conversion();
}
循环队列的顺序表示及实现
循环队列的基本出队入队操作,出队:队头位标Q.front增1,入队:队尾位标Q.rear增1
入队:Status EnQueue (SqQueue &Q, ElemType e)
判断队列是否满(Q.rear+1)%Q.maxSize== Q.front
将e放入队尾位标指向的空间,
并将队尾位标实现循环后移Q.rear=(Q.rear+1)%Q.maxSize;
出队:Status DeQueue (SqQueue &Q, ElemType &e)
判断队列是否为空Q.front==Q.rear
将队头位标指向的元素赋值给e
并且队头位标实现循环后移Q.front=(Q.front+1)%Q.maxSize;
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef int ElemType;
typedef int Status;
//----- 队列的顺序存储表示 -----
#define MAXQSIZE 30 // 存储空间的初始分配量
typedef struct {
ElemType *base;//头指针作为队头指针指向队头
int front;//队头位标
int rear;//队尾位表,指示队尾位标
int maxSize;// 存储容量
} SqQueue;
// 构造一个空队列 Q
Status InitQueue(SqQueue &Q){
Q.base=(ElemType*)malloc(MAXQSIZE*sizeof(ElemType));//分配存储空间
if(!Q.base) exit(OVERFLOW);
Q.front=Q.rear=0;//置Q为空队列
Q.maxSize = MAXQSIZE;
return OK;
}
//判队列是否为空
Status QueueEmpty (SqQueue Q) {
if(Q.rear==Q.front) return TRUE;
else return FALSE ;
}
//入队函数
Status EnQueue (SqQueue &Q, ElemType e) {
//若当队列不满,在队列的尾元素之后,插入元素e为新的队列尾元素
if((Q.rear+1)%Q.maxSize==Q.front) return ERROR;//循环队列满了,返回ERROE
Q.base[Q.rear]=e;//否则将e插入队尾位标指向的位置
Q.rear=(Q.rear+1)%Q.maxSize; //队尾位标加1后移,当Q.rear为Q.maxSize时,令Q.rear回到0的位置
return OK;
}
//出队函数
Status DeQueue (SqQueue &Q, ElemType &e) {
//请在此填写代码,将该算法补充完整,参见书本和课件相关章节
//若队列不空,则删除队列Q中的头元素,用e返回其值
if(Q.front==Q.rear) return ERROR;//队空报错
e=Q.base[Q.front];//将front所指向的元素赋值给e
Q.front=(Q.front+1)%Q.maxSize;//Q.front循环加1当Q.front为Q.maxSize时,令Q.front回到0的位置
return OK;
}
//输出循环队列函数
void OutQueue(SqQueue Q)
{ ElemType e;
if(QueueEmpty(Q)){
printf("这是一个空队列!");
}
else{
while(!QueueEmpty(Q)){
DeQueue(Q,e);
printf("%6d", e);
}
printf("\n");
}
}
//主函数
int main()
{ SqQueue q;
int cord;
ElemType a;
printf("第一次使用必须初始化!\n");
do{
printf("\n 主菜单 \n");
printf(" 1 初始化循环队列 ");
printf(" 2 进队一个元素 ");
printf(" 3 出队一个元素 ");
printf(" 4 结束程序运行 ");
printf("\n------------------------------------------------------------------\n");
printf("请输入您的选择( 1, 2, 3, 4)");
scanf("%d",&cord);
printf("\n");
switch(cord){
case 1:
InitQueue(q); //调用初始化算法;
OutQueue(q);
break;
case 2:
printf("请输入要插入的数据元素:a=");
scanf("%d",&a);
EnQueue (q, a); //调用进队算法;
printf("%d 进队之后的队列:",a);
OutQueue(q);
break;
case 3:
DeQueue (q, a); //调用出队算法;
printf("队头元素 %d 出队之后的队列:",a);
OutQueue(q);
break;
case 4:
exit(0);
}
}while (cord<=4);
}
顺序表(栈表)——采用顺序存储结构表示的线性表
插入:Status ListInsert_Sq(SqList &L, int i ,ElemType e)
在顺序表L的第i位置插入一个元素
检验合法性 i<1||i > L.length+1
length-i+1个元素后移,从最后一个元素开始
在位置i处插入元素e
表长加1
删除:Status ListDelete_Sq(SqList &L, int i, ElemType &e)
删除顺序表L的表尾元素,并用参数e返回其值
判断是否是空表0==L.length
被删除的元素赋值给e
表长减1
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;
//----- 顺序表的顺序存储表示 -----
#define LIST_INIT_SIZE 100 // 存储空间的初始分配量
#define LISTINCREMENT 10 // 存储空间的分配增量
typedef struct
{
ElemType *elem; // 存储空间的基址
int length; // 表长
int size;// 存储容量
int increment; // 扩容时,增加的存储容量
} SqList; //顺序表
// 构造一个顺序表
Status InitSqlist(SqList &L)
{
L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));//分配存储空间
if(!L.elem) exit (OVERFLOW);//分配失败
L.length = 0;//置空表
L.size = LIST_INIT_SIZE;
L.increment = LISTINCREMENT;
return OK;
}
// 判顺序表是否为空表
Status ListEmpty(SqList L)
{
if (L.length==0) return OK;
else return ERROR;
}
//顺序表插入函数
Status ListInsert_Sq(SqList &L, int i ,ElemType e)
{
if (i<1||i > L.length+1) { //存储的下表超出顺序表实际的长度
printf("插入的下标超出顺序表的实际长度");
return false;
}
for (int a=L.length; a>=i; a--) {
L.elem[a] = L.elem[a - 1]; //将第i个元素及之后的元素后移,后移length-i+1个元素
}
L.elem[i-1] = e; //在位置i处放入e
L.length++;//长度加1
return true;
}
//顺序表删除元素函数
Status ListDelete_Sq(SqList &L, int i, ElemType &e)
{
if(0==L.length)
return ERROR;
e=L.elem[i-1];
for(int j=i;j<=L.length-1;j++)//将第i个元素之后的所有元素前移,前移length-i个元素
{
L.elem[j-1]=L.elem[j];
}
--L.length;//长度减一
return OK;
}
//输出顺序表函数
void OutList_Sq(SqList L)
{ int i;
//ElemType e;
if(ListEmpty(L)){
printf("这是一个空表!");
}
else
{
printf("顺序表为:");
for(i=0;i<L.length;i++)
printf("%6d",L.elem[i]);
}
printf("\n");
}
//查找元素的位置
//在顺序表L中顺序查找数据元素e,成功时返回该元素在表中第一次出现的位置,否则返回-1
int Search(SqList L,ElemType e)
{
int i=0;
while(i<L.length&&L.elem[i]!=e) i++;//顺序查找e
if(i<L.length)return i;
else return -1;
}
//主函数
int main()
{
SqList L;
int cord,i,j; ElemType a,b;
printf("第一次使用必须初始化!\n");
do{
printf("\n 主菜单 \n");
printf(" 1 初始化顺序表 ");
printf(" 2 插入一个元素 ");
printf(" 3 删除一个元素 ");
printf(" 4 查询一个元素 ");
printf(" 5 结束程序运行 ");
printf("\n-------------------------------------------------------------------\n");
printf("请输入您的选择( 1, 2, 3, 4,5) :");
scanf("%d",&cord);
printf("\n");
switch(cord)
{
case 1:
InitSqlist(L);
OutList_Sq(L);
break;
case 2:
printf("\n请输入要插入的插入位置和数据元素(如:3 20):");
scanf("%d %d",&i,&a);
ListInsert_Sq(L,i,a);
printf("\n插入%d元素之后的:",a);
OutList_Sq(L);
break;
case 3:
printf("\n请输入要删除的数据元素的位置(如: 3):");
scanf("%d",&i);
ListDelete_Sq(L,i,a);
printf("\n删除第%d个位置的元素之后:",i);
OutList_Sq(L);
break;
case 4:
printf("请输入一个要查询的数");
scanf("%d",&b);
j= Search(L,b);
printf("位置在:%d",j);
break;
case 5:
exit(0);
}
}while (cord<=4);
return 1;
}