“线性结构是一个有序数据元素的集合。常用的线性结构有:线性表,栈,队列,双队列,串。关于广义表、数组,是一种非线性的数据结构。同时,线性结构也是数据结构里面最基础,也是最简单的一种数据结构类型,其中典型的一种叫做线性表。
那么什么是线性表呢??
线性表及其实现
定义:“线性表(Linear List)”是由同一类型的数据元素构成的有序序列的线性结构。
线性表中元素的个数称为线性表的长度;
当一个线性表中没有元素(长度为0)时,称为空表;
表的起始位置称表头,表的结束位置称表尾。
数据对象集:线性表是 n (≥0)个元素构成的有序序列( a1, a2, ,an ) ; ai+1称为 ai的直接后继, ai-1为 ai的直接前驱;直接前驱和直接后继反映了元素之间一对一的邻接逻辑关系。
1、List MakeEmpty():初始化一个新的空线性表L;
2、ElementType FindKth(List L, int i ):根据指定的位序i,返回相应元素 ;
3、Position Find( List L, ElementType X ):已知X,返回线性表L中与X相同的第一个元素的相应位序i;若不存在则返回空;
4、bool Insert(List L, ElementType X, int i):指定位序i前插入一个新元素X;成功则返回true,否则返回false;
5、bool Delete(List L, int i):删除指定位序i的元素;成功则返回true,否则返回false;
6、int Length( List L ):返回线性表L的长度n。
操作的实现
利用数组的连续存储空间顺序存放线性表的各元素。
typedef struct LNode *PtrToLNode;
struct LNode{
ElementType Data[MAXSIZE];
Position Last;
};
typedef PtrToLNode List;
List L;
**1.**初始化一个新的空线性表L
List MakeEmpty()
{ List L;
L = (List)malloc(sizeof(struct LNode));//申请一个数组空间
L->Last = -1;
return L;
}
**2.**查找(已知X,返回线性表L中与X相同的第一个元素的相应位序i;若不存在则返回空; )
Position Find( List L, ElementType X )
{ Position i = 0;
while( i <= L->Last && L->Data[i]!= X )
i++;
if ( i > L->Last )
return -1; /* 如果没找到,返回错误信息 */
else return i; /* 找到后返回的是存储位置 */
}
**3.**插入(指定位序i前插入一个新元素X;成功则返回true,否则返回false)
步骤
先把i-1以后的所有元素往后移懂,然后再将元素X插到i-1的位置(注意:必须从后往前移动)
bool Insert( List L, ElementType X, int i )
{ Position j;
if ( L->Last == MAXSIZE-1) {
/* 表空间已满,不能插入 */
printf("表满");
return false;
}
if ( i<1 || i>L->Last+2 ) {
/* 检查插入位序的合法性:是否在1~n+1。n为当前元素个数,即Last+1 */
printf("位序不合法");
return false;
}
for( j=L->Last; j>=i-1; j-- ) /*Last指向序列最后元素 */
L->Data[j+1] = L->Data[j]; /* 将位序i及以后的元素顺序向后移动 */
L->Data[i-1] = X; /* 新元素插入第i位序,其数组下标为i-1 */
L->Last++; /* Last仍指向最后元素 */
return true;
}
**4.**删除(删除指定位序i的元素;成功则返回true,否则返回false;)
bool Delete( List L, int i )
{ Position j;
if( i<1 || i>L->Last+1 ) { /* 检查空表及删除位序的合法性 */
printf("位序%d不存在元素", i );
return false;
}
for( j=i; j<=L->Last; j++ )
L->Data[j-1] = L->Data[j]; /*将位序i+1及以后的元素顺序向前移动*/
L->Last--; /* Last仍指向最后元素 */
return true;
}
线性表用链式存储实现
typedef struct LNode *PtrToLNode;
struct LNode{
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
List L;
**1.**求表长
int Length(List L)
{
Position p;
int cnt=0;
p=L;
while(p){
p=p->Next;
cnt++;
}
return cnt;
}
**2.**查找
List FindKth(int k,int ptrl)
List FindKth(int k,int ptrl)
{
List p=ptrl;
int i=1;
while(p!=NULL&&i<k)
{
p=p->Next;
i++;
}
if(i==k)
return p;
else
return NULL;
}
List Find(ElementType X,List PtrL)
{
List p=PtrL;
while(p!=NULL&&p->Data!=X)
{
p=p->Next;
}
return p;
}
广义表(用Tag来区分后面的是单元素,还是另一个广义表)
【定义】上述这类表就是一种“广义表(Generalized List)”。
广义表是线性表的推广。
广义表与线性表一样,也是 由n个元素组成的有序序列。
不同点在于,对于线性表而言, n个元素都是基本的单元素;
而在广义表中,这些元素不仅可以是单元素也可以是另一个广义表;
typedef struct GNode *PtrToGNode;
typedef PtrToGNode GList;
struct GNode {
int Tag; /* 标志域:0表示该结点是单元素;1表示该结点是广义表 */
union { /* 子表指针域Sublist与单元素数据域Data复用,即共用存储空间 */
ElementType Data;
GList Sublist;
} URegion;
PtrPtrToGNode Next; /* 指向后继结点 */
};
多重链表
2:堆栈(先进后出)
栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成。
注意:再入堆栈时要判断是否已经堆满,在出堆栈时要判断是否为空,同时,用数组可以同时用一个头结点一个尾结点同时入栈。
栈的链式存储结构实际上就是一个单链表,叫做链栈。插入和删除操作只能在链栈的栈顶进行;栈顶指针Top就是链表的头指针。
注意:在入栈时不需要判断是否已经堆满,出栈时要判断是否为空,只能用一个头结点入栈,不能用尾节点入栈。
表达式求值原则:如果碰到优先级低于栈顶的,就出栈,如果碰到括号,只有左括号碰到右括号时才出列,如果碰到同等优先级,左边的优先。
例题2-1:表达式求值
模拟简单运算器的工作。假设计算器只能进行加减乘除运算,运算数和结果都是整数,四种运算符的优先级相同,按从左到右的顺序计算。输入格式:输入在一行中给出一个四则运算算式,没有空格,且至少有一个操作数。遇等号”=”说明输入结束。输出格式:在一行中输出算式的运算结果,或者如果除法分母为0或有非法运算符,则输出错误信息“ERROR”。
输入样例:1+2*10-10/2=
输出样例:10
#include <stdio.h>
int main()
{
int i,sum,is=0;
char o='0';//运算符初始值为'0'
scanf("%d",&sum);
while(o!='=')
{
scanf("%c",&o);
if(o=='=')
break;
scanf("%d",&i);
if(o=='+')
sum=sum+i;//题目要求不考虑计算优先级,可以直接从左到右顺序计算
else if(o=='-')//所以可以依次判断运算符,将新输入变量加到原来的结果上
sum=sum-i;
else if(o=='*')
sum=sum*i;
else if(o=='/')
{//判断除法除数是否合法
if(i!=0)//判断不为零的情况,而不是判断为零的情况
sum=sum/i;
else
//printf("ERROR");
is=1;//设置判断点,输出时判断后输出
}
else
is=1;//输入除了+ —* / 之外的符号,视为非法错误输入
//printf("ERROR");
}
if(is==1)
printf("ERROR");
else
printf("%d\n",sum);
return 0;
}
3.队列(先进先出)
“队列(Queue)” 是具有一定操作约束的线性表,插入和删除操作有一定要求:只能在一端插入,而在另一端删除。
栈的链式存储结构实际上就是一个单链表,叫做链栈。插入和删除操作只能在链栈的栈顶进行;栈顶指针Top就是链表的头指针。
不带头结点的链式队列出队操作的一个示例
bool IsEmpty( Queue Q )
{ return ( Q->Front == NULL);
}
ElementType DeleteQ( Queue Q )
{ Position FrontCell;
ElementType FrontElem;
if ( IsEmpty(Q) ) {
printf("队列空"); return ERROR;
}
else {
FrontCell = Q->Front;
if ( Q->Front == Q->Rear ) /* 若队列只有一个元素 */
Q->Front = Q->Rear = NULL; /* 删除后队列置为空 */
else
Q->Front = Q->Front->Next;
FrontElem = FrontCell->Data;
free( FrontCell ); /* 释放被删除结点空间 */
return FrontElem;
}
}
多项式加法运算
Polynomial PolyAdd (Polynomial P1, Polynomial P2)
{
Polynomial front, rear, temp;
int sum;
rear = (Polynomial) malloc(sizeof(struct PolyNode));//为方便表头插入,先产生一 个临时空结点作为结果多项 式链表头
front = rear; /* 由front 记录结果多项式链表头结点 */ while ( P1 && P2 ) /* 当两个多项式都有非零项待处理时 */
switch ( Compare(P1->expon, P2->expon) )
{
case 1:
Attach( P1->coef, P1->expon, &rear);//P1中的数据项指数较大
P1 = P1->link;
break;
case -1:
Attach(P2->coef, P2->expon, &rear);//P2中的数据项指数较大
P2 = P2->link;
break;
case 0:
sum = P1->coef + P2->coef;//两数据项指数相等
if ( sum )//注意判断系数和是否为0
Attach(sum, P1->expon, &rear);
P1 = P1->link;
P2 = P2->link;
break;
} /* 将未处理完的另一个多项式的所有节点依次复制到结果多项式中去 */ for ( ; P1; P1 = P1->link )
Attach(P1->coef, P1->expon, &rear);
for ( ; P2; P2 = P2->link )
Attach(P2->coef, P2->expon, &rear);
rear->link = NULL;
temp = front;
front = front->link; /*令front指向结果多项式第一个非零项 */ free(temp); /* 释放临时空表头结点 */ return front;
/* 将未处理完的另一个多项式的所有节点依次复制到结果多项式中去 */ for ( ; P1; P1 = P1->link )
Attach(P1->coef, P1->expon, &rear);
for ( ; P2; P2 = P2->link )
Attach(P2->coef, P2->expon, &rear);
rear->link = NULL;
temp = front;
front = front->link; /*令front指向结果多项式第一个非零项 */ free(temp); /* 释放临时空表头结点 */ return front;
}