数据类型 —— 第二章 线性表及其数据存储

目录

线性表

顺序表

总结:

队列


线性表

线性表的定义:

用数据元素的有限序列表示

顺序表

顺序表的定义:

线性表采用顺序存储的方式存储就称之为顺序表。顺序表是将表中的结点一次存放在计算机内存中一组地址的存储单元中。

顺序表的实现:

C语言中的数组存储顺序表。C语言中数组的下标是从0开始的,为了方便,将顺序表中各结点的序号改为和对应数组元素的下标号一致。这样,一个就是一个长度为n的数据表。

顺序表的存储结构表示:

#define MAXSIZE 100

//定义顺序表结构 
typedef int datatype;

typedef struct{
    datatype a[MAXSIZE];
    int size;
}sequence_list;

顺序表的初始化(置空):

//置空(初始化)顺序表 
void init_sequence_list(sequence_list *slt)
{
    slt -> size = 0;
}

在顺序表后部进行插入操作:

//顺序表的插入操作 
void insert_sequence_list(sequence_list *slt,datatype x)
{
    if(slt->size == MAXSIZE){
        printf("顺序表是满的");
        exit(1);
 
    }
    slt->a[slt->size] = x;
    slt->size = slt->size + 1;
}

打印顺序表中各结点的值

//打印顺序表中各个结点 
void print_sequence_list(sequence_list slt)
{
    int i;
    if(!slt.size) printf("\n顺序表是空的!");
    else
    for(i = 0 ; i < slt.size ; i ++) printf("%d",slt.a[i]);   
}

在顺序表中查找结点值为x的结点位置

//查找顺序表中值为x的结点的位置 
int find_num_sequence_list(sequence_list slt, datatype x)
{
    int i = 0;
    while(slt.a[i] != x &&i < slt.size) i ++;
    return(i < slt.size?i:-1);
}

取得顺序表中第i个结点的值

//去顺序表中第 i 个结点的值 
int get_data_pos(sequence_list slt,int i)
{
    if(i < 0 ||i > slt.size)
    {
        printf("指定位置的结点不存在!");
        exit(1);
    }
    else 
        return slt.a[i];
}

顺序表的插入运算

//顺序表的插入运算 
void insert_pos_sequence_list(sequence_list *slt,int position , datatype x)
{
    int i;
    if(slt->size == MAXSIZE)
    {
        printf("顺序表是满的!无法插入!");
        exit(1);
    }
    if(position < 0 || position > slt->size)
    {
        printf("插入位置不存在!");
        exit(1);
    }
    for(i = slt -> size ; i < position ; i --) slt -> a[i] = slt -> a[i - 1];
    slt -> a[position] = x;
    slt -> size ++;
}

注:插入的时间复杂度为O(n/2)

顺序表的删除操作:

//顺序表的删除运算 
void delete_pos_sequence_list(sequence_list *slt , int position)
{
    int i;
    if(slt -> size == 0)
    {
        printf("顺序表是空的!");
        exit(1);
    }
    if(position < 0 || position >= slt->size)
    {
        printf("指定的删除位置不存在!");
        exit(1);
    }
    for(i = position ; i < slt -> size - 1; i ++) slt -> a[i] = slt -> a[i + 1];
    slt -> size --; 
}

栈的定义:栈是一种特殊的额线性表,对于这种线性表规定它的插入运算和删除运算均在线性表的同一端进行,进行插入和删除的一端称为栈顶,另一端被称为栈底。栈的插入操作和删除操作分别简称进栈和出栈。

注:女性知识竞赛小票、只是对表插入和删除操作的位置进行了限制,并没有限定插入和删除操作的时间

栈的实现方式一般有两种:顺序存储和链式存储

顺序栈:就是在顺序表的基础上对插入和删除操作限制它们在顺序表的同一端进行,所以通顺序表一样也可用一维数组表示。

注:一般的可以设定一个足够大的一维数组存储栈,数组中下标为0的元素就是栈底,对于栈顶,可以设一个top指针指示它。

 为了方便设定top指针所指的位置是下一个将要插入的结点的存储位置,这样,当top=0时就是一个空的栈。

栈的存储结构

#define MAXSIZE 100;
typedef int datatype;
typedef struct{
    datatype a[MAXSIZE];
    int top;
}sequence_stack;

栈的初始化

void init_sequence_stack(sequence_stack *st)
{
    st -> top = 0;
} 

判断栈是否为空

int is_empty_stack(sequence_stack st)
{
    return(st.top?0:1); 
}

取得栈顶的结点值

datatype get_top(sequence_stack st)
{
    if(empty_stack(st))
    {
        printf("\n栈是空的!");
        exit(1);
    }
    else
        return st.a[st.top - 1];
}

栈的插入操作

void push(sequence_stack *st , datatype x)
{
    if(st -> top == MAXSIZE)
    {
        printf("\n the sequence stack is full!");
        exit(1);
    }
    st -> a[st - > top] = x;
    st -> top ++;
}

栈的删除操作

void pop(sequence_stack *st)
{
    if(st -> top == 0)
    {
        printf("\nThe sequence stack is empty!");
        exit(1);
    }
    st -> top --;
}

栈的应用之一——括号的匹配

​
int match_kuohao(char c[])
{
	int i = 0;
	sequence_stack s;
	init_sequence_stack(&s);
	while(c[i]!='#')
	{
		switch(c[i])
		{
			case'{': push(&s , c[i]); break;
			case'[': push(&s , c[i]); break;
			case'(': push(&s , c[i]); break;
			case'}':
				if(!is_empty_sequence_stack(s) && get_top == '{')
				{
					pop(&s);
					break;
				}
				else return 0;
			case']':
				if(!is_empty_sequence_stack(s) && get_top == '[')
				{
					pop(&s);
					break;
				}
				else return 0;
			case')':
				if(!is_empty_sequence_stack(s) && get_top == '(')
				{
					pop(&s);
					break;
				}
				else return 0;
		}
		i ++;	
	}
	return (is_empty_sequence_stack(s));//栈空则匹配,否则不匹配 
 } 

​

栈的应用之二——算数表达式的求值

  • 前缀表示法
  • 中缀表示法
  • 后缀表示法
void postfix(char e[] , char f[])
{
	int i = 0 , j = 0;
	char opst[100];
	int top , t;
	top = 0;
	opst[top] = '#';
	top ++;
	while(e[i] != '#')
	{
		if((e[i] >= '0' && e[i] <= '9')||e[i] == '.')
			f[j ++] = e[i];
		else if(e[i] == '(')
		{
			t = top - 1;
			while(opst[t] != '(')
			{
				f[j ++] = opst[-- top];
				t = top - 1;
			}
			top --;
		}
		else if(is_operation(e[i]))
		{
			f[j ++] = ' ';
			while(priority(opst[top - 1]) >= priority(e[i]))
				f[j ++] = opst[-- top];
			opst[top] = e[i];
			top ++;
		}
		i ++;
	}
	while(top) f[j ++] = opst[-- top];
 } 

将字符数据转换为小数数据

Double readnumber(char f[] , int  *i)
{
	double x = 0.0;
	int k = 0;
	while(f[*i] >= '0' && f[*i] <= '9')
	{
		x = x * 10 + (f[*i] - '0');
		(*i) ++;
	}
	if(f[*i] == '.')
	{
		(*i) ++;
		while(f[*i] >= '0' && f[*i] <= '9')
		{
			x = x * 10 + (f[*i] - '0');
			(*i) ++;
			k ++;
		}
	}
	while(k != 0)
	{
		x = x / 10.0;
		k = k - 1;
	}
	return (x);
}

后缀表达式求值:

double evalpost(char f[])
{
	double obst[100];//操作数栈 
	int top = 0 , i = 0;
	double x1 , x2;
	while(f[i] != '#')
	{
		if(f[i] >= '0' && f[i] <= '9')
		{
			obst[top] = readnumber(f , &i);
			top ++;
			i ++;
		}
		else if(f[i] == ' ') i ++;
		else if(f[i] == '+')
		{
			x2 = obst[-- top];
			x1 = obst[-- top];
			obst[top] == x1 + x2;
			top ++;
			i ++;
		}
		else if(f[i] == '-')
		{
			x2 = obst[-- top];
			x1 = obst[-- top];
			obst[top] == x1 + x2;
			top ++;
			i ++;
		}
		else if(f[i] == '*')
		{
			x2 = obst[-- top];
			x1 = obst[-- top];
			obst[top] == x1 + x2;
			top ++;
			i ++;
		}
		else if(f[i] == '/')
		{
			x2 = obst[-- top];
			x1 = obst[-- top];
			obst[top] == x1 + x2;
			top ++;
			i ++;
		}
	} 
	return onst[0];
}

总结:

  • 操作数之间的相对次序不变;
  • 运算符的相对次序不同
  • 中缀丢失了括弧信息致使运算的次序不确定(有二义性
  • 前缀的运算规则为连续出现的两个操作数和在它们之前且紧靠它们的运算符构成一个最小表达式;先找操作数,后找运算符
  • 后缀的运算规则为:运算符在式中出现的顺序恰为表达式的运算顺序;每个运算符在式中和它之前出现且紧靠它的两个操作数构成一个最小的表达式

队列

对列的定义:

队列的是一种特殊的线性表,它的特殊性在于队列的插入和删除操作分别在表的两端进行插入的那一端为队尾,删除的那一端称为队首。队列的插入操作和删除操作分别简称进队和出队。

队列的存储结构:

#define MAXSIZE 100
typedef int datatype;
typedef struct
{
    datatype a[MAXSIZE];
    int front;
    int rear;
}sequence_queue;

打印队列的结点值:

void print_sequence_queue(sequence_sequeue sq)
{
    int i;
    if(is_empty_sequence_queue(sq))
    {
        printf("\顺序队列是空的");
    }
    else
    for (i = sq.front ; i < sq.real ; i ++) printf("%5d",sq.a[i]);
}

判断队列是否为空

int is_empty_sequence_queue(sequence_queue sq)
{
    return (sq.front == sq.rear?1:0);
}

队列存储的初始化

void init_sequence_queue(sequence_queue *sq)
{
    sq -> front = sq -> rear = 0;
}

队列的插入操作:

void insert_sequence_queue(sequence_queue *sq,datatype x)
{
    int i;
    if(sq->rear == MAXSIZE)
    {
        printf("\n顺序循环队列是满的");
    }
    sq -> a[sq -> rear] = x;
    sq -> rear = sq -> rear + 1
}

注:列满和列空条件如果都是

rear == front 

,会产生二义性

解决方案:

牺牲一个数组元素的空间,即若数组的大小是MAXSIZE,则该数组所表示的循环队列最多允许存储MAXSIZE - 1个结点。(队尾指针指向队头指针的上一个位置时就认为队列已满)这样,循环队列满的条件是

(rear + 1) % MAXSIZE == front

循环列空的条件则是:

rear == front

循环队列插入操作的实现:

void insert_sequence_cqueue(sequence_queue *sq,datatype x)
{
    int i;
    if((sq -> rear + 1)% MAXSIZE == sq -> front)
    {
        printf("\n顺序循环队列是满的!无法进行插入操作!");
        exit(1);
    }
    sq -> a[sq -> rear] = x;
    sq -> rear = (sq ->rear + 1)% MAXSIZE;
}

循环队列删除操作的实现:

void delete_sequence_cqueue(sequence_queue *sq)
{
    if(sq -> front == sq -> rear)
    {
        printf("\循环队列是空的!无法进行删除!");
        exit(1);
    }
    sq -> front = sq -> (front + 1)% MAXSIZE;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值