連結串列,順序表的基本操作及其實現的棧與佇列
阿新 • • 發佈:2019-02-14
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,永遠指向存在值的最上面的地址,佇列有兩個指標,首指標和尾指標,尾進頭出,尾指標永遠指向最後一個入隊元素下一個的空位置,頭指標永遠指向即將出隊的元素,除非隊空,一定有值。