线性结构(第三章)

教材:数据结构(第二版)主编:陈越

线性结构:
所谓线性结构就是数据像一条线一样串在一起,是一个抽象的概念,其中每一个元素都是直接前驱和直接后驱,数据的存储分为逻辑结构和物理结构,物理结构包括了顺序存储(在内存中用地址连续的一块存储空间顺序存放数据)和链式存储(不需要连续的存储空间),逻辑结构包括了诸如线性表,树,集合,图等,而常见的数组其实是线性表的一种实现,但是线性表和数组之间没有从属关系。线性表的典型应用就是堆栈和队列;顺序存储和逻辑存储的优缺点(原帖地址

本章讲解了:线性表(List)的顺序存储(顺序表)和链式存储(单链表,双向链表,广义表,多重链表),堆栈(Stack)的顺序存储(双堆栈)和链式存储,队列(queue)的顺序存储和链式存储(循环队列)

线性表:
主要操作集:
1.初始化生成:List MakeEmpty();
2.按位序查找: ElementType FindKth(List L, int i );
3.按数值查找: Position Find(List L, ElementType X); //typedef int Position;
4.插入: bool Insert(List L, ElementType X, int i);
5.删除: bool Delete(List L, int i);
6.返回长度:int Length(List L);

线性表的顺序存储:(顺序表)
顺序表的结构:

typedef enum{true, false} bool;
#define ERROR -1
typedef struct LNode
{
	ElementType Data[MAXSIZE];
	Position Last;//保存最后一位的位置
}*PtrToNode;
typedef PtrToNode List;

初始化:
List MakeEmpty( )
{
	List L;
	L = (List)malloc(sizeof(struct LNode));
	L->Last = -1;
	return L;
}

查抄:
ElementType FindKth(List L, ElementType X )
{
	Position i =0;
	while(i<=Last&&L->Data[i]!=x)
	{
	i++;
	}
	if(i>Last)return ERROR;
	else return i;
}

插入:
bool Insert(List L, ElementType X, int i )
{
	Position m = L->Last;
	//表是否已满
	if(L->Last==MAXSIZE-1)
	{
	printf("表满");
	return false;
	}
	//插入位置合法性
	if(i<1||i>L->Last2)
	{
	printf("输入位置非法");
	return false;
	}
	while(m>=i-1)
	{
	L->Data[m+1] = L->Data[m];
	m--;
	}
	L->Data[i-1] = X;
	L->Last++;
	return true;
}
在等概率条件下,平均移动元素的次数为(n/2)
该方法的时间复杂度为 O(n)

删除:
bool Delete(List L, int i)
{
	Position m = i ;
	if(L->Last == -1)
	{
	printf("空表");
	return false;
	}
	if(i<1||i>L->Last+1)//其实可以把判断空表的条件和这个合并,因为当Last==1时,i如果不大于0,就会返回这是非法操作,但是i必须是大于0的
	{
	printf("输入位置非法");
	return false
	}
	while(m>=L->Last)
	{
	L->Data[m] = L->Data[m+1];
	m++;
	}
	L->Last--;
	return true;
}
在等概率条件下,平均移动元素的次数为((n-1)/2)
该方法的时间复杂度为 O(n)

线性表的链式存储:
(单链表)

单链表的结构:
typedef struct LNode
{
ElementType Data;
PtrToNode Next;
}*PtrToNode;
typedef PtrToNode List;
typedef PteToNode Position; //结点的地址

求表长:
int Length(List L)
{
	int count = 0;
	Position P;
	P = L;//无头结构的链表L,则P指向第一个结点
	while(P) 
	{
	P=P->Next;
	count++;
	}
	return count;
}

查找:
按序号查找:
#define ERROR -1
ElementType FindKth(List L, int i)
{
	Position P = L;
	int count = 1;
	while(P && count<i)
	{
	P = P->Next;
	count++;
	}
	if((count == i) && P)return P->Data;
	else return ERROR;
}
按值查找:
#define ERROR NULL

Position Find(List L,ElementType X)
{
	Position P = L;
	while(P&&(P->Data!=X)) P = P->Next;
	if(P)return P;
	else return ERROR;
}
上述两种查找方法的时间复杂度均为 O(N)

插入:(注意这里最好增加一个空的头节点,当出现插入在表头的特殊情况的时候,因为表头指针指向的值会因为添加和删除发生变化,假如插入失败,返回值为NULL,L = Insert(L,X,i)是不可以的,所以解决办法要么增加头节点,返回值改为返回bool类型,要么函数参数为List *L,即采用双指针的形式)
//假设这里给出的L是带头节点的链表
bool Insert(List L, ElementType X, int i )
{
	Position tempNode,P;
	int count = 0;
	P = L;//P指向表头,如果P指向第一结点,那么不能检测插入在第一个节点之前的情况
	while(P && count<i-1)//找到待插入序列的前一个序列
	{
	P = P->Next;
	count++;
	}
	if(P==NULL||count!=i)
	{
	printf("输入参数非法");
	return false;
	}else
	{
	tempNode = (Position)malloc(sizeof(struct LNode));
	tempNode->Data = X;
	tempNode->Next = P->Next;
	P->Next = tempNode;
	return true;
	}
}

删除:
bool Delete(List L, int i)
{
	Position P,tempNode;
	P = L;
	int count = 0;
	while(P && count<i-1)
	{
	P = P->Next;
	count++;
	}
	if(P == NULL || count!=i-1 || P->Next == NULL)
	{
	printf("输入非法");
	return false;
	}else
	{
	tempNode = P->Next;
	P->Next = tempNode->Next;
	free(tempNode);
	return true;
	}
}

广义表和多重链表
广义表采用链式存储的方法,用到了联合体(union),一般来说会有两个指针域,多重链表每个结点有多个指针域,但是包含两个指针域的链表并不一定是多重链表,多重链表多用在例如树,图这样复杂的数据结构。
例如,稀疏矩阵的数据结构:

typedef enum{Head,Term}NodeTag;

struct TermNode
{
	int Row,Col;
	ElementType Value;
};

typedef struct MNode * PtrToNode;
struct MNode
{
	PtrToNode Down,Right;
	NodeTag Tag;
	union
	{
		PtrToNode Next;
		struct TermNode Term;
	}URegion;
};
typedef PtrToMNode Matrix;
Matrix HeadNode[MAXSIZE];

堆栈
了解中缀表达式转前缀表达式和后缀表达式的过程:
转后缀表达式:从左到右看,遇到数字输出,遇到符号进栈,括号要匹配,当进栈的符号优先级小于栈顶符号,将栈内符号输出一直到栈顶符号优先级小于等于进栈的符号,入栈,以此类推,最后采用LIFO(Last In First Out)的原则输出
转前缀表达式:从右到左看,遇到数组输出,遇到符号进栈,括号要匹配,进栈的符号优先级小于栈顶符号,将栈内符号输出一直到栈顶符号优先级小于等于进栈的符号,入栈,以此类推,最后采用LIFO(Last In First Out)的原则输出

堆栈的操作集:
1.生成:Stack CreateStack(int MaxSize);
2.是否满栈: bool IsFull(Stack S);
3.入栈: bool Push(Stack S, ElementType X);
4.是否空栈:bool IsEmpty(Stack S);
5.出栈:ElementType Pop(Stack S);

堆栈的顺序存储实现:

typedef int Position;
typedef struct SNode 
{
	ElementType* Data;
	Position Top;
	int MaxSize;
}*Stack;

入栈:
bool IsFull(Stack S)
{
	return(S->Top == MaxSize-1);
}
bool Push(Stack S, ElementType X)
{
	if(IsFull(S)) 
	{
	printf("堆栈满");
	return false;
	}
	S->Data[++(S->Top)] = X;//注意不要写成(S->Top)++
	return true;
}

出栈:
#define ERROR -1
bool IsEmpty(Stack S)
{
	return(S->Top == -1);
}
ElementType Pop(Stack S)
{
	if(IsEmpty(S)) 
	{
	printf("栈空");
	return ERROR;
	}
	return(S->Data[(S->Top)--]);
}

堆栈的链式存储:
同样有一个top的指标用来指示栈顶,但是这里的top指针就是头指针,每一次的出栈和入栈都是从头指针这里开始,这里我们使用带头节点的链表

typedef Stack PtrToNode;
typedef struct SNode
{
	ElementType Data;
	PtrToNode Next;
}*Stack;

bool IsEmpty(Stack S)
{
	return(S->Next == NULL);
}

bool Push(Stack S, ElementType X)
{
	PtrToNode tempNode;
	PtrToNode P = S;
	tempNode = (PtrToNode)malloc(sizeof(struct SNode));
	tempNode ->Data = X;
	tempNode ->Next = P->Next;
	P->Next = tempNode;
	return true; 
}

ElementType Pop(Stack S)
{
	if(IsEmpty(S))
	{
	printf("栈空");
	return false;
	}
	PtrToNode tempNode;
	tempNode = S->Next;
	ElementType topValue;
	topValue = tempNode->Data;
	S->Next = tempNode->Next;
	free(tempNode);
	return topValue;
}

双堆栈的顺序存储:

typedef int Position;
typedef struct SNode
{
	ElementType * Data;
	Position Top1,Top2;
	int Maxsize;
}* PtrToNode;
typedef PtrToNode Stack;
//Tag作为指标,指示插入第一个栈还是第二个栈,两栈满的条件是Top1,Top2相遇
bool Push(Stack S,ElementType X, int Tag)
{
	if(S->Top1 == (S->Top2-1))
	{
	printf("堆栈满");
	return false;
	}
	if(Tag == 1) S->Data[++(S->Top1)]=X;
	else if(Tag == 2) S->Data[++(S->Top2)]=X;
	return true;
}

ElementType Pop(Stack S, int Tag)
{
	if(Tag == 1)
	{
	if(S->Top1 == -1) printf("该堆栈空");
	return ERROR;
	}else return S->Data[(S->Top1)--];
	}else if(Tag == 2)
	{
	if(S->Top2 == S->Maxsize) printf("该栈为空");
	return ERROR;
	}else return S->Data[(S->Top2)--];
	}
}

队列

队列的顺序存储:
插入和删除:

typedef int Position;
typedef struct QNode
{
	ElementType * Data;
	Position Front,Rear;
	int Maxsize;
}*PtrToNode;
typedef PtrToNode Queue;

Queue CreateQueue(int Maxsize)
{
	Queue Q = (Queue)malloc(sizeof(struct QNode));
	Q->Data=(ElementType*)malloc(Maxsize*sizeof(ElementType));
	Q->Maxsize = Maxsize;
	Q->Front = Q->Rear = 0;
	return  Q;
}

bool IsFull(Queue Q)
{
	return((Q->Rear+1)%Q->Maxsize == Q->Front);
}

bool IsEmpty(Queue Q)
{
	return (Q->Rear == Q->Front);
}

bool AddQ(Queue Q, ElementType X)
{
	if(IsFull(Q))
	{
	printf("栈满");
	return false;
	}else
	{
	Q->Rear = (Q->Rear + 1)%Q->Maxsize;
	Q->Data[Q->Rear] = X;
	return true;
	}
}

Elementype DeletedQ(Queue Q)
{
	if(IsEmpty(Q))
	{
	printf("队列空");
	return ERROR;
	}else
	{
	Q->Front = (Q->Front + 1)%Q->Maxsize;
	return Q->Data[Q->Front];
	}
}

队列的链式存储:
(不带头节点)

typedef struct Node
{
	ElementType Data;
	PtrToNode Next;
}*PtrToNode;
typedef PtrToNode Position;

typedef struct QNode
{
	Position Front,Rear;
	int Maxsize;
}*PtrToNode;
typedef PtrToNode Queue;

bool IsEmpty(Queue Q)
{
	return(Q->Front== NULL);
}

ElementType DeleteQ(Queue Q)
{
Position P;
ElementType value;
if(IsEmpty(Q))return ERROR;
else
{
	P = Q->Front;
	if(Q->Front == Q->Rear) Q->Front = Q-Rear =NULL;
	else Q->Front = Q->Front->Next;
	value = P->Data;
	free(P);
	return value;
}
}

猜你喜欢

转载自blog.csdn.net/m0_43429389/article/details/107519559