链表,顺序表的基本操作及其实现的栈与队列

来源:互联网 发布:宏编程鼠标lol有用吗 编辑:程序博客网 时间:2024/06/08 03:24

1,顺序表

在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,永远指向存在值的最上面的地址,队列有两个指针,首指针和尾指针,尾进头出,尾指针永远指向最后一个入队元素下一个的空位置,头指针永远指向即将出队的元素,除非队空,一定有值。


阅读全文
0 0
原创粉丝点击