链表,顺序表的基本操作及其实现的栈与队列
2017-12-23 22:03
856 查看
1,顺序表
在c里面,这一部分也就是静态表和动态表的实现,插入,删除有丁点意思。
静态表靠数组和长度实现(注意长度这一点,因为它反映了当前表内容长度,十分重要)
动态表依靠申请连续空间实现(结构体内部包括首地址,当前规模以及长度)
插入:
2,链表:
链表结构体很简单:
首先是首插法和尾插法:
接下来,是循环链表,双链表,循环双链表的基本操作,并不复杂,也就是在基本的尾插法上加一些操作即可实现。
注意:在双向链表中,得到节点只能通过priori或是next得到先序节点或是后继节点,所以我们在连好后/先节点与插入节点之前不可断链。
概括而言:顺序是s的后继连向p的后继,p的后继的前驱连上s(先把p的后继处理),s的前驱指向p,p的后继指向s。(之后把p连向s);
3,栈与队列
栈和队列基于顺序表抑或是链表实现的,他们不过是在后者的操作的基础上加上特定的操作罢了。
typedef struct{
char a[MAXSIZE];
int top;
}SqStack;
typedef struct{
int *base;
int *top;
int stacksize;
}SqStack1;
以上是顺序栈的结构体,静态的top初始化为-1,动态的top=base指向申请空间首位置。
注意:入栈是先升指针再入栈。(*(++S.top)=e)
出栈是先赋值给参数再降指针(*(S.top--)=e)(反了,懒得改能看懂就ok)
链栈不很常见,头节点+首插法就ok,存取对象都是头节点的next即可。
队列:
以普通静态队列为例:
typedef struct{
int elem[100];
int rear,front;
int SqSize;
}SqQueue;以上结构体;
入队出队:void Basic_Operate(SqQueue &S,int a,int m)
{
if(m==1)
{
S.elem[S.top++]=a;
}
if(m==0)
{
a=S.elem[S.rear++];
printf("%d",a);
}
}循环动态队列:
typedef struct{
int *base;
int top;
int rear;
}CircleQueue;以上结构体;
int init_CQ(CircleQueue &CQ)
{
CQ.base=(int *)malloc(sizeof(100));
CQ.top=0;
CQ.rear=0;
}
int EnQueue(Circle &CQ,int a)
{
if((CQ.rear+1+100)%100==CQ.top){
return ERROR;
}
else
{
CQ.base[CQ.rear]=a;
CQ.rear=(CQ.rear+1+100)%100;
return 1;
}
}
int DeQueue(CirCleQueue &CQ,int a)
{
if(CQ.top==CQ.rear)
{
return ERROR;
}
else
{
a=CQ.base[top];
CQ.top=(CQ.top+1+100)%100;
return a;
}
}
以上初始化/插入/删除操作;
注意:1,判满条件:(CQ.rear+1)%MAXSIZE==CQ.top;
2,判空条件:CQ.rear==CQ.top;
3,CQ.top=(top+1)%MAXSIZE;
最后,在脑海里要形成栈和队列各自指针的位置,栈只有一个头指针top,永远指向存在值的最上面的地址,队列有两个指针,首指针和尾指针,尾进头出,尾指针永远指向最后一个入队元素下一个的空位置,头指针永远指向即将出队的元素,除非队空,一定有值。
在c里面,这一部分也就是静态表和动态表的实现,插入,删除有丁点意思。
静态表靠数组和长度实现(注意长度这一点,因为它反映了当前表内容长度,十分重要)
动态表依靠申请连续空间实现(结构体内部包括首地址,当前规模以及长度)
插入:
int *p; p=&(w.a[k-1]); int *q; for(q=&(w.a[w.length-1]);q>=p;--q) { *(q+1)=*q; } *q=m; ++w.length;删除同理
2,链表:
链表结构体很简单:
typedef struct Node{ int data; struct Node *next; }; typedef Node* Linkedlist;
首先是首插法和尾插法:
int Touinsert(Linkedlist &l) { Lnode* r,s,m; l=r; for(int i=0;i<=length;i++) { s=(Lnode *)malloc(sizeof(Lnode)); s->data=i; s->next=L; r=L; //! } for(int i=0;i<=length;i++) { s=(Lnode *)malloc(sizeof(Lnode)); s->data=i; L->next=s; s->next=m; m=s; } }//头插法对于存不存在头节点没有特殊需求,反而头结点会导致头插法不那么方便 /* int Weiinsert(LInkedlist &l) { Lnode *r,m; r=L; for(int i=0;i<=length;i++) { s=(Lnode *)malloc(sizeof(Lnode)); r->next=s; r=s; } }//尾插法在此处就有问题——我们不可能r=L后(此时L为NULL)通过对r的操作改变L,首结点的本质是使得初定义的指针可以和L共同指向一个有意义的节点,通过初定义的指针直接影响L */ int Weiinsert(LInkedlist *l) { L=(Lnode*)malloc(sizeof(Lnode));//注意定义首节点的方法 Lnode *r,*s; r=L; for(int i=0;i<=length;i++) { s=(Lnode *)malloc(sizeof(Lnode)); s->data=i; r->next=s; r=s; } }如上所述,尾插法记得加首节点,会令操作简化一些,并且逻辑不会冲突。
接下来,是循环链表,双链表,循环双链表的基本操作,并不复杂,也就是在基本的尾插法上加一些操作即可实现。
void init_CircleLinkedList(Linkedlist &l1,int t) { Linkedlist m,a; m=(Linkedlist)malloc(sizeof(Node)); m->data=t; l1=m; //!!! m->next=NULL; for(int i=0;i<t;i++) { a=(Linkedlist)malloc(sizeof(Node)); a->data=i; m->next=a; m=m->next; if(i==t-1) { m->next=l1->next; continue; } } } void init_DoubleLInkedlist(Linkedlist1 &l2,int t) { Linkedlist1 m,a; m=(Linkedlist1)malloc(sizeof(Node1)); m->data=t; l2=m; m->next1=NULL; m->prior=NULL; for(int i=0;i<t;i++) { a=(Linkedlist1)malloc(sizeof(Node1)); a->data=i; m->next1=a; a->prior=m; m=a; if(i==t-1) { m->next1=NULL; } } } void init_DoubleLCircleInkedlist(Linkedlist1 &l2,int t) { Linkedlist1 m,a; m=(Linkedlist1)malloc(sizeof(Node1)); m->data=t; l2=m; m->next1=NULL; m->prior=NULL; for(int i=0;i<t;i++) { a=(Linkedlist1)malloc(sizeof(Node1)); a->data=i; m->next1=a; a->prior=m; m=a; if(i==t-1) { m->next1=l2; l2->next->prior=m; } } }最后,我特别粘贴一张双链表的插入操作的图:
注意:在双向链表中,得到节点只能通过priori或是next得到先序节点或是后继节点,所以我们在连好后/先节点与插入节点之前不可断链。
概括而言:顺序是s的后继连向p的后继,p的后继的前驱连上s(先把p的后继处理),s的前驱指向p,p的后继指向s。(之后把p连向s);
3,栈与队列
栈和队列基于顺序表抑或是链表实现的,他们不过是在后者的操作的基础上加上特定的操作罢了。
typedef struct{
char a[MAXSIZE];
int top;
}SqStack;
typedef struct{
int *base;
int *top;
int stacksize;
}SqStack1;
以上是顺序栈的结构体,静态的top初始化为-1,动态的top=base指向申请空间首位置。
注意:入栈是先升指针再入栈。(*(++S.top)=e)
出栈是先赋值给参数再降指针(*(S.top--)=e)(反了,懒得改能看懂就ok)
链栈不很常见,头节点+首插法就ok,存取对象都是头节点的next即可。
队列:
以普通静态队列为例:
typedef struct{
int elem[100];
int rear,front;
int SqSize;
}SqQueue;以上结构体;
入队出队:void Basic_Operate(SqQueue &S,int a,int m)
{
if(m==1)
{
S.elem[S.top++]=a;
}
if(m==0)
{
a=S.elem[S.rear++];
printf("%d",a);
}
}循环动态队列:
typedef struct{
int *base;
int top;
int rear;
}CircleQueue;以上结构体;
int init_CQ(CircleQueue &CQ)
{
CQ.base=(int *)malloc(sizeof(100));
CQ.top=0;
CQ.rear=0;
}
int EnQueue(Circle &CQ,int a)
{
if((CQ.rear+1+100)%100==CQ.top){
return ERROR;
}
else
{
CQ.base[CQ.rear]=a;
CQ.rear=(CQ.rear+1+100)%100;
return 1;
}
}
int DeQueue(CirCleQueue &CQ,int a)
{
if(CQ.top==CQ.rear)
{
return ERROR;
}
else
{
a=CQ.base[top];
CQ.top=(CQ.top+1+100)%100;
return a;
}
}
以上初始化/插入/删除操作;
注意:1,判满条件:(CQ.rear+1)%MAXSIZE==CQ.top;
2,判空条件:CQ.rear==CQ.top;
3,CQ.top=(top+1)%MAXSIZE;
最后,在脑海里要形成栈和队列各自指针的位置,栈只有一个头指针top,永远指向存在值的最上面的地址,队列有两个指针,首指针和尾指针,尾进头出,尾指针永远指向最后一个入队元素下一个的空位置,头指针永远指向即将出队的元素,除非队空,一定有值。
相关文章推荐
- 实验3:栈和队列的基本操作实现及其应用——顺序队列和链队列
- 实验三:栈和队列的基本操作实现及其应用——顺序栈
- 实验4:栈和队列的基本操作实现及其应用——链栈
- 实验4:栈和队列的基本操作实现及其应用之《链栈》
- 不带头节点的单链表及其基本操作(Java实现)
- 实验4:栈和队列的基本操作实现及其应用之《顺序栈》
- 实验3:栈和队列的基本操作实现及其应用——十进制转换为二进制
- 实验三 栈和队列的基本操作实现及其应用 (1)
- 双链表的实现及其基本操作
- 实验4:栈和队列的基本操作实现及其应用之《链队列》
- 数据结构笔记(一)线性表的顺序表示和基本操作及其顺序表实现的集合运算(A-B)U(B-A)实例
- 实验4:栈和队列的基本操作实现及其应用之《排号叫号管理》
- 数据结构:实验四栈和队列的基本操作实现及其应用
- bo3-4.c 用单链表的基本操作实现链队列(存储结构由c3-2.h定义)的基本操作(9个)
- 实验4:栈和队列的基本操作实现及其应用——进制转换以及实验总结
- 顺序队列的基本操作实现c++
- c语言实现链表及其基本操作
- C语言实现单链表的基本操作及其部分面试题
- 线性表的基本操作实现 - 链表与顺序表
- 顺序队列(循环队列)基本操作实现 C语言