单链表(二)
6、单链表的建立
尾插法
LinkList List_TailInsert(LinkList *L){
int x;
L = (LinkList) malloc(sizeof (LNode)); //建立一个头结点
LNode *s, *r = L; //r为指向表尾结点的指针
scanf("%d", &x);
while(x != 9999){ //取一个特殊值表示输入结束
s=(LNode *) malloc(sizeof (LNode));
s->data = x;
r->next = s; //在r结点之后插入元素x
r = s;
scanf("%d", &x);
}
r->next = NULL; //最后的尾结点置空
return L;
}
头插法
LinkList List_HeadInsert(LinkList L){ //逆向建立单链表
LNode *s;
int x;
L = (LinkList) malloc(sizeof (LNode)); //建立一个头结点
L->next = NULL; //初始化为空链表
scanf("%d", &x);
while(x != 9999){ //取一个特殊值表示输入结束
s=(LNode *) malloc(sizeof (LNode));
s->data = x;
s->next = L->next;
L->next = s; //将新结点插入表中,L为头指针
scanf("%d", &x);
}
return L;
}
二、双链表
1、建立双连表
typedef struct DNode{
int data;
struct DNode *prior, *next;
}DNode, *DLinklist;
bool InitDLinklist(DLinklist L){
L = (DNode *) malloc (sizeof (DNode)); //分配一个头结点
if(L == NULL) //内存不足,分配失败
return false;
L->prior = NULL; //头结点的prior永远指向NULL
L->next = NULL; //头结点之后暂时还有结点
return true;
}
bool Empty(DLinklist L){ //带头结点的双链表判断是否为空
if(L->next == NULL)
return true;
else
return false;
}
2、双链表的插入
bool InsertNextDNode(DNode *p, DNode *s){
if(p == NULL || s==NULL)
return false;
s->next = p->next;
if(p->next != NULL) //如果p结点有后继结点
p->next->prior = s;
s->prior = p;
p->next = s;
}
3、双链表的删除
bool DeleteNextDNode(DNode *p){
if(p==NULL)
return false;
DNode *q = p->next; //找到p的后继结点q
if(q==NULL)
return false; //p没有后继
p->next = q->next;
if(q->next != NULL) //趴结点不是最后一个结点
q->next->prior = p;
free(q); //释放结点空间
return true;
}
4、销毁一个双链表
void DestoryList(DLinklist L){
while (L->next != NULL)
DeleteNextDNode(L);
free(L); //释放头结点
L=NULL; //头指针指向NULL
}
三、循环链表
1、循环单链表
typedef struct LNode{
int data;
struct LNode *next;
}LNode, *LinkList;
bool InitList(LinkList L){ //初始化一个循环单链表
L = (LNode *) malloc(sizeof (LNode)); //分配一个头结点
if(L==NULL)
return false;
L->next = L; //头结点next指向有结点
return true;
}
bool Empty(LinkList L){
if(L->next == L)
return true;
else
return false;
}
bool isTail(LinkList L, LNode *p){ //判断结点p是否为循环单链表的表尾结点
if(p->next==L)
return true;
else
return false;
}
2、循环双链表
typedef struct DNode{
int data;
struct DNode *prior, *next;
}DNode, *DLinklist;
bool InitDLinkList(DLinklist L){
L = (DNode *) malloc(sizeof (DNode));
if(L==NULL)
return false;
L->prior = L;
L->next = L;
return true;
}
bool Empty(DLinklist L){
if(L->next == L)
return true;
else
return false;
}
bool isTail(DLinklist L, DNode *p){
if(p->next == L)
return true;
else
return false;
}
四、静态链表
1、定义一个静态链表
两种方式:
#define MaxSize 10 //静态链表的最大长度
struct Node{ //静态链表结果类型的定义
int data; //存储数据元素
int next; //下一个元素的数值下标
};
typedef struct Node SLinkList[MaxSize];
typedef struct {
int data;
int next;
}SLinkList[MaxSize];
2、静态链表的优缺点
优点:增、删操作不需要大量移动元素
缺点:不能随机存取,只能从头结点开始依次往后查找;容量固定不变
五、栈
1、定义顺序栈
#define MaxSize 10 //定义栈中元素的最大个数
typedef struct{
int data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针
}SqSrack;
2、栈的初始化
void InitStack(SqStack *S){
S->top = -1; //初始化栈顶指针
//S->top = 0; 第二种初始化方式,此时top指向的是下一个可以放元素的位置
}
3、栈的判空操作
bool StackEmpty(SqStack S){ //判断栈空
if(S.top == -1) //第二种方式判空条件:S.top == 0
return true;
else
return false;
}
4、新元素入栈
bool Push(SqStack *S, int x){
if(S->top == MaxSize-1) //栈满,报错
return false;
S->top = S->top + 1; //指针先加1
S->data[S->top] = x; //新元素入栈
// S->data[++S->top = x; 可替换上两行
// S->data[S.top++] = x; 第二种方式的进栈操作
return true;
}
5、出栈操作
bool Pop(SqStack *S, int x){ //出找操作
if(S->top == -1)
return false;
x = S->data[S->top]; //栈顶元素先出栈
S->top = S->top - 1; //指针再减1
// x = S->data[S->top--]; 可替换上两行
// x = S->data[--S->top]; 第二种方式的出栈操作
return true;
}
6、取栈顶元素
bool GetTop(SqStack S, int x){ //取栈顶元素
if(S.top == -1)
return false;
x = S.data[S.top]; //x记录栈顶元素
return true;
}
7、顺序栈的缺点:栈的大小不可变
8、共享栈:指两个栈共享一片内存空间
初始化共享栈:
#define MaxSize 10
typedef struct{
int data[MaxSize];
int top0; //0号栈栈顶指针
int top1; //1号栈栈顶指针
}ShStack;
初始化栈顶指针:
void InitShStack(ShStack *S){
S->top0 = -1;
S->top1 = MaxSize;
}
共享栈栈满条件:top0 + 1 == top1
9、链栈
链栈一般不带头结点:
typedef struct StackNode{ //定义一个不带头结点的链表栈
int data;
struct StackNode *next;
}SNode, *StackList;
typedef struct{
StackList top;
int count;
}LinkStack;
bool InitStackNode(StackList *S){ //初始化一个链表栈
S = NULL;
return true;
}
bool Empty(StackList S){ //判断一个链表栈是否为空
return (S == NULL);
}
入栈(头插法):
bool StackPush(LinkStack *S, int e){
StackList s = (StackList) malloc (sizeof (StackNode));
s->data = e;
s->next = S->top; //把当前栈顶指针赋给新结点的后继
S->top = s; //将新结点置为栈顶指针
S->count++;
return true;
}
出栈(删除第一个结点):
bool StackPop(StackList *S, int *e){
StackList p;
if(StackEmpty(*S))
return false;
*e = S->top->data; //保存当前栈顶元素的值
p = S->top; //将当前栈顶指针指向的结点赋值给p
S->top = S->top->next; //将栈顶指针向下移一位
free(p); //释放结点p
S->count--;
return true;
}
10、队列
定义一个队列:
#define MaxSize 10
typedef struct {
int data[MaxSize]; //用静态数组存放队列元素
int front, rear; //队头指针和队尾指针
}SqQueue;
void InitQueue(SqQueue *Q){ //初始化队列
Q->rear = Q->front = 0; //初始时,队头、队尾指针指向0
}
bool QueueEmpty(SqQueue Q){ //判断队列是否为空
if(Q.rear == Q.front) //队空条件
return true;
else
return false;
}
bool EnQueue(SqQueue *Q, int x){ //入队
if((Q->rear+1)%MaxSize == Q->front) //判断队列满的条件
return false;
Q->data[Q->rear] = x; //新元素插入队尾
Q->rear = (Q->rear+1)%MaxSize; //队尾指针向后移一位,若到最后一个元素,则转到第一个元素位置
return true;
}
bool DeQueue(SqQueue *Q, int x){ //出队
if(Q->rear == Q->front) //判断队空
return false;
x = Q->data[Q->front]; //将队头元素赋值给e
Q->front = (Q->front+1)%MaxSize; //队头指针向后移一位,如果到最后一位则转到第一个元素位置
return true;
}
bool GetHead(SqQueue Q, int x){ //返回队头元素的值,用x返回
if(Q.rear == Q.front)
return false;
x = Q.data[Q.front];
return true;
}