一、链表
typedef int ElementType;
typedef ElementType ET;
1.单向链表
//定义
typedef struct Node *List;
struct Node{
ET Data;
List Next;
};
//申请内存空间
List p=(List)malloc(sizeof(struct Node));
//插入结点
//将结点t插在结点p之后
t->Next=p->Next;
p->Next=t;
//在链表表头插入一个结点t
t->Next=head;
head=t;
//删除结点
//首先找到被删除结点的前面一个结点p,然后删除p之后那个结点
t=p->Next;
p->Next=t->Next;
free(t);
//如果删除的是第一个结点
t=head;
head=head->Next;
free(t);
//单向链表的遍历
p=head;
while(p!=NULL){
······
对p所指的结点信息进行处理
······
p=p->Next;
}
注意:有时为了程序处理方便,使用带头结点的单向链表(第一个结点是空结点)。
2.双向链表
//定义
typedef struct DNode *DList;
struct DNode{
ET Data;
DList Next;
DList Previous;
};
//插入操作
//在p后插入新结点t(方法:一个正对勾,一个倒对勾)
t->Next=p->Next;
p->Next=t;
t->Next->Previous=t;
t->previous=p;
二、线性表
1.线性表顺序存储(下标从0开始)
typedef struct LNode *List;
struct LNode{
ET Data[MAXSIZE];
int Last; //最后一个元素的数组下标
};
//顺序表的初始化
List MakeEmpty()
{
List L=(List)malloc(sizeof(struct LNode));
L->Last=-1;
return L;
}
//查找
//与定值X相等的数据元素,返回数组下标
int Find(List L,ET X)
{
int i=0;
while(i<=L->Last&&L->Data[i]!=X)
i++;
if(i>L->Last) return -1;
else return i;
}
//时间复杂度:查找成功的平均比较次数为(1+2+···+n)/n=(n+1)/2,
//即平均时间复杂度为O(n);
//插入
//在表第i个元素(下标i-1)位置上插入新元素X
bool Insert(List L,ET X,int i)
{
if(L->Last==MAXSIZE)
{
printf("表满");
return false;
}
if(i<1||i>L->Last+2)
{
printf("位序不合法");
return false;
}
//后移元素
for(int j=L->Last;j>=i-1;j--)
L->Data[j+1]=L->Data[j];
//插入元素
L->Data[i-1]=X;
L->Last++;
return true;
}
//时间复杂度:O(n)
//删除
//将表中第i个元素删除
bool Delete(List L,int i)
{
if(i<1||i>L->Last+1)
{
printf("第%d个位置不存在元素",i);
return false;
}
//前移
for(int j=i;j<=L->Last;j++)
L->Data[j-1]=L->Data[j];
L->Last--;
return true;
}
//时间复杂度:O(n)
2.线性表链式存储
//定义
typedef struct LNode * List;
struct LNode{
ET Data;
List Next;
};
//求表长
int Length(List L)
{
int cnt=0;
List p=L;
while(p)
{
p=p->Next;
cnt++;
}
return cnt;
}
//时间复杂度:O(n)
//查找
//按序号查找,得到第K个元素的值
ET FindKth(List L,int K)
{
int cnt=1;
List p=L;
while(p&&cnt<K)
{
p=p->Next;
cnt++;
}
if((cnt==K)&&p)
return p->Data;
else
return -1;
}
//按值查找,返回该结点
List Find(List L,ET X)
{
List p=L;
while(p&&p->Data!=X)
p=p->Next;
return p;
}
//时间复杂度:O(n)
//插入
//第i个位置上插入X
//避免将表头插入作为一种特殊情况处理,就为表头增加一个空结点
bool Insert(List L,ET X,int i)
{
List pre,tmp;
int cnt=0; //注意:无空头结点为1
//查找第i-1个位置
pre=L;
while(pre&&cnt<i-1)
{
pre=pre->Next;
cnt++;
}
if(pre==NULL||cnt!=i-1)
{
printf("插入位置参数错误\n");
return false;
}
else
{ //若i为1,pre就指向表头
//插入新结点
tmp=(List)malloc(sizeof(struct LNode));
tmp->Data=X;
tmp->Next=pre->Next;
pre->Next=tmp;
return true;
}
}
//带头结点的链式表删除
//删除第i个元素
bool Delete(List L,int i)
{
List pre,tmp;
int cnt=0;
//查找第i-1个位置
pre=L;//指向表头
while(pre&&cnt<i-1)
{
pre=pre->Next;
cnt++;
}
if(pre==NULL&&cnt!=i-1&&pre->Next==NULL)
{
printf("插入位置参数错误\n");
return false;
}
else
{ //将结点删除
tmp=pre->Next;
pre->Next=tmp->Next;
free(tmp);
return true;
}
}
三、广义表与多重链表
1.广义表
//定义
typedef struct GNode *GList;
struct GNode{
int Tag;//标志域:0表示该结点是单元素;1表示该结点是广义表
union{ //子表指针域Sublist与单元素数据域Data复用,即共用存储空间
ET Data;
GList Sublist;
}URegion;
GList Next; //指向后继结点
};
2.多重链表:存在结点属于多个链的链表。
下图为稀疏矩阵多重链表结点结构
//稀疏矩阵的数据结构定义
typedef enum {Head,Term} NodeTagl
struct TermNode{ //非零元素结点
int Row,Col;
ET Value;
};
typedef struct MNode *Matrix;//稀疏矩阵类型定义
struct MNode{
Matrix Down,Right;
NodeTag Tag;
union{//Head对应Next指针;Term对应非零元素结点
Matrix Next;
struct TermNode Term;
}URegion;
};
Matrix HeadNode[MAXSIZE];
//MAXSIZE是矩阵最大规模,即行数、列数的最大值
//HeadNode是为了能快速指向各行或列链表头结点的指针数组
四、堆栈
先入后出
1.栈的顺序存储实现
//定义
typedef struct SNode *Stack;
struct SNode{
ET *Data;//存储元素的数组
int Top;//栈顶指针
int MaxSize;//堆栈最大容量
};
//创建空堆栈
Stack CreateStack(int MaxSize)
{
Stack S=(Stack)malloc(sizeof(struct SNode));
S->Data=(ET *)malloc(MaxSize*sizeof(ET));
S->Top=-1;
S->MaxSize=MaxSize;
return S;
}
//入栈操作Push
bool IsFull(Stack S)
{
return(S->Top==S->MaxSize-1);
}
bool Push(Stack S,ET X)
{
if(IsFull(S))
{
printf("堆栈满");
return false;
}
else
{
S->Data[++(S->Top)]=X;
return true;
}
}
//出栈操作Pop
bool IsEmpty(Stack S)
{
return (S->Top==-1);
}
ET Pop(Stack S)
{
if(IsEmpty(S))
{
printf("堆栈空");
return -1;
}
else
return (S->Data[(S->Top)--]);
}
2.堆栈的链式存储实现
//栈顶指针Top就是链表的头指针
//为了简便算法,链栈可以带一空的表头结点
//定义
typedef struct SNode * Stack;
struct SNode{
ET Data;
Stack Next;
};
//构建一个堆栈的头结点
Stack CreateStack()
{
Stack S;
S=(Stack)malloc(sizeof(struct SNode));
S->Next=NULL;
return S;
}
//将新元素压入堆栈
bool IsEmpty(Stack S)
{
return (S->Next==NULL);
}
bool Push(Stack S,ET X)
{
Stack TmpCell;
TmpCell=(Stack)malloc(sizeof(struct SNode));
TmpCell->Data=X;
TmpCell->Next=S->Next;
S->Next=TmpCell;
return true;
}
//删除并返回堆栈S的栈顶元素
ET Pop(Stack S)
{
Stack FirstCell;
ET TopElem;
if(IsEmpty(S))
{
printf("堆栈空");
return -1;
}
else
{
FirstCell=S->Next;
TopElem=FirstCell->Data;
S->Next=FirstCell->Next;
free(FirstCell);
return TopElem;
}
}
五、队列
先进先出
1.队列的顺序存储实现
/*为了解决队尾溢出而实际上数组仍然有空余空间的问题一般在队列的顺序存储结构中采用循环队列的形式;
当插入或删除操作的作用单元达到数组末端时,用公式“Rear(或Front)%数组长度”取余运算就可以实现折返到起始单元*/
//而当Front与Rear值相等时,队列可能为空或者满,无法判别
/*解决方法:少用一个元素空间,此时的状态是队尾指针加1就会从后面赶上队头指针;
队满条件是:(Rear+1)%数组长度等于Front.
队空条件是:Rear等于Front.*/
//定义
typedef struct QNode * Queue;
struct QNode{
ET *Data;
int Front,Rear;
int Maxsize;
};
//创建Queue CreateQueue(int MaxSize)
{
Queue Q=(Queue)malloc(sizeof(struct QNode));
Q->Data=(ET *)malloc(MaxSize*sizeof(ET));
Q->Front=Q->Rear=0;
Q->MaxSize=MaxSize;
return Q;
}
//插入
bool IsFull(Queue Q)
{
return ((Q->Rear+1)%Q->MaxSize==Q->Front);
}
bool AddQ(Queue Q,ET X)
{
if(IsFull(Q))
{
printf("队列满");
return true;
}
else
{
Q->Rear=(Q->Rear+1)%Q->MaxSize;
Q->Data[Q->Rear]=X;
return true;
}
}
//删除
bool IsEmpty(Queue Q)
{
return Q->Front==Q->Rear;
}
ET DeleteQ(Queue Q)
{
if(IsEmpty(Q))
{
printf("队列空");
return false;
}
else
{
Q->Front=(Q->Front+1)%Q->MaxSize; //注意:此处的Front指向的点是空结点,加1后是要删除的结点
return Q->Data[Q->Front];
}
}
2.队列的链式存储实现
//定义
//队列的头(Front)必须指向链表的头结点,队列的尾(Rear)指向链表的尾结点
typedef struct Node *PtrToNode;
struct Node{
ET Data;
PtrToNode Next;
};
typedef struct QNode * Queue;
struct QNode{
PtrToNode Front,Rear;
int MaxSize;
};
//入队:在尾部插入结点
//出队:在头部删除结点
//下为不带头结点的链式队列出列
bool IsEmpty(Queue Q)
{
return (Q->Front==NULL);
}
ET DeleteQ(Queue Q)
{
PtrToNode FrontCell;
ET FrontElem;
if(IsEmpty(Q))
{
printf("队列空");
return -1;
}
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;
}
}