数据结构——线性表的链式表示
線性表的定義
線性表是具有相同數據類型的n(n >= 0)個數據元素的有限序列。其中n為表長,當n = 0時,該線性表是一個空表。若用L命名線性表,其一般表示為:L = (a1, a2, ..., ai, ai+1, ..., an)。其中a1是唯一的”第一個”數據元素,an是唯一的”最后一個”數據元素。除第一個元素外,每個元素有且僅有一個直接前驅。除最后一個元素外,每個元素有且僅有一個直接后繼。
線性表的特點如下:
(1)表中元素的個數有限。
(2)表中元素具有邏輯上的順序性,在序列中各元素排序有其先后次序,即為線性結構。
(3)表中元素都是數據元素,每一個元素都是單個元素。
(4)表中元素具有抽象性。即僅討論元素間的邏輯關系,不考慮元素的內容。
線性表是一種邏輯結構,表示元素之間一對一的相鄰關系。順序表和鏈表是指存儲結構。在接觸一種新的數據結構類型時,都應該分別從其邏輯結構、存儲結構和對數據的操作三方面著手。
?
線性表的鏈式存儲稱為單鏈表。它是通過一組任意的存儲單元來存儲線性表中的數據元素。為了建立起數據元素之間的線性關系,對每個鏈表結點,除了存放元素自身的信息之外,還需要存放一個指向其后繼的指針。單鏈表邏輯結構上連續(xù)而其物理結構上不連續(xù)。其結點類型可描述為:
typedef struct Lnode{int data;struct Lnode *next; }Lnode, *LinkList;利用單鏈表可以解決順序表需要大量的連續(xù)存儲空間的缺點,但是單鏈表附加指針域,也存在浪費存儲空間的缺點。由于單鏈表的元素是離散地分布在存儲空間中的,所以單鏈表是非隨機存儲的存儲結構,即不能直接找到表中某個特定的結點。
頭結點和頭指針的區(qū)別:不管帶不帶頭結點,頭指針始終指向鏈表的第一個結點,而頭結點是帶頭結點鏈表中的第一個結點,結點內通常不存儲信息。
引入頭結點不需擔心的問題:
(1)由于開始結點的位置被存放在頭結點的指針域中,所以在鏈表的第一個位置上的操作和在表的其他位置上的操作一致,無須進行特殊處理。
(2)無論鏈表是否為空,其頭指針是指向頭結點的非空指針(空表中頭結點的指針域為空),因此空表和非空表的處理也是統(tǒng)一的。
引入頭結點不僅不用擔心上述問題,還能簡化操作,具體表現(xiàn)在對鏈表第一個數據元素進行頻繁的刪除和插入。
?
棧的定義
棧:是只允許在一端進行插入或刪除操作的線性表。首先棧是一種線性表,但是限定這種線性表只能在一端進行插入和刪除操作。它的一個明顯的操作特性可以概括為后進先出。
棧的鏈式存儲稱為鏈棧,鏈棧的優(yōu)點是便于多個棧能充分的利用存儲空間,且不存在棧上溢的情況。通常使用單鏈表實現(xiàn),并規(guī)定所有操作都是在單鏈表的表頭進行。采用鏈棧,便于結點的插入和刪除。鏈棧的操作與鏈表類似,熟悉鏈表的頭插法和刪除第一個元素等操作后,鏈棧很容易就能看懂。這里就不過多說明了,直接看后面的代碼。棧的鏈式存儲類型可描述為:
typedef struct Linknode{Elemtype data; ????????????//數據域struct Linknode *next; ??????//指針域 }*LinkStack;?
隊列的定義
隊列:簡稱為隊,也是一種操作受限的線性表,只允許在表的一端進行插入,而在另外一端進行刪除。其操作特性是先進先出。
隊列的鏈式表示稱為鏈隊列,它實際上是一個同時帶有隊頭指針和隊尾指針的單鏈表。頭指針指向隊頭結點,尾指針指向隊尾結點,即單鏈表的最后一個結點。隊列的鏈式存儲可描述為:
typedef struct{ ??????????? ?//隊列的結點Elemtype data;struct LinkNode *next; }LinkNode;typedef struct{LinkNode *front,*rear; ???//隊列的隊頭和隊尾指針 }LinkQueue; //用一個結構體將首尾指針封裝起來便于操作當Q.front == NULL且Q.rear == NULL時,鏈式隊列為空。根據隊列的性質,在建立隊列的時候使用鏈表的尾插法。出隊時,首先判斷隊是否為空,若不空,則取出隊頭元素,將其從鏈表中摘除,并讓Q.front指向下一個結點(若該結點為最后一個結點,則置Q.front和Q.rear都為NULL)。入隊時,建立一個新結點,將新結點插入到鏈表的尾部,并改讓Q.rear指向這個新插入的結點(若原隊列為空隊,則令Q.front也指向該結點)。
不設頭結點的鏈隊列操作上比較麻煩,因為它要頻繁的在隊頭刪除元素。所以,通常將鏈式隊列設計成一個帶頭結點的單鏈表,這樣插入和刪除操作就能簡化了。鏈棧和鏈隊列就是對單鏈表的刪除和增添進行了限制而已,其本質還是單鏈表的操作。所以這一塊只要看懂了單鏈表的代碼,鏈棧和鏈隊列很好理解。
?
單鏈表 Linklist.c ?
#include <stdio.h> #include <stdlib.h>typedef char ElemType; //單鏈表中各個節(jié)點中數據域的數據類型//單鏈表結點結構體的定義 typedef struct Node {ElemType data;struct Node *next; }Node,Linknode,*LinkList;#define ERROR 0 #define OK 1//單鏈表的初始化 //一般來說,都會為單鏈表增加一個頭結點,目的:操作時的方便。因此,初始化時,可以建立一個頭結點,并設置其指針域指向空void InitList(LinkList *H) //H用來接收主程序中待初始化單鏈表的頭指針變量的地址 {*H = (LinkList)malloc(sizeof(Node)); //建立頭結點(*H)->next = NULL; //建立空的指針域 }//頭插法建立單鏈表 void CreateFromHead(LinkList H) {Node *s = NULL;int flag = 1;char c;//當flag = 0時,不再插入數據while(flag){c = getchar();//判斷c的值,若是$則將flag置0,否則插入數據if (c != '$'){s = (Node *)malloc(sizeof(Node));if (!s){printf("Memory is not enough!");exit(0);}s->data = c;s->next = H->next;H->next = s;}else{flag = 0;}} }//尾插法建立單鏈表 //首先一個結點指針變量r,指向頭結點,每次插入的時候,讓r指向插入的結點 void CreateFromTail(LinkList H) {int flag = 1;char c;Node *r = NULL,*s = NULL;r = H;while(flag){c = getchar();if (c != '$'){s = (LinkList)malloc(sizeof(Node));if (!s){printf("Memory is not enough!");exit(0);}s->data = c;r->next = s;r = s;}else{flag = 0;}}r->next = NULL; }//在單鏈表中查找第i個結點 //如果查找成功,則返回第i個結點地址,否則返回NULL Node* Get(LinkList L,int i) {int j = 0;Node *r = NULL;r = L;while(r->next != NULL && j < i){r = r->next;j++;}if (i == j){return r;}else{return NULL;} }//在單鏈表中查找值等于key的結點 //如果查找成功,則返回該節(jié)點的地址,否則返回NULL Node * Locate(LinkList L,ElemType key) {Node *r = NULL;r = L->next;/**從第一個結點開始查找,如果第一個結點不存在,直接返回NULL,如果查找到最后循環(huán)退出,返回NULL,*如果中途找到與該值相等的結點,返回該結點的地址。*/while(r != NULL){if (r->data != key){r = r->next;}else{break;}}return r; }//在單鏈表中進行插入運算 //若要在單鏈表中的第i個位置插入結點,首先要找到第i-1個結點,然后在該結點之后插入結點即可 int InsList(LinkList L,int i,ElemType e) {int j = 0;Node *pre = L;Node *s = NULL;/**要想在第i個位置插入結點,必須先找到第i-1個結點*/while(pre != NULL && j < i-1){pre = pre->next;j++;}if (j != i-1){printf("插入位置不合理!");return ERROR;}s = (LinkList)malloc(sizeof(Node));if (!s){printf("Memory is not enough!");exit(0);}s->data = e;s->next = pre->next;pre->next = s;return OK; }//單鏈表的刪除操作 //要想刪除第i個位置的結點,還是要先找到第i-1個位置的結點 int DelList(LinkList L,int i,ElemType *e) {Node *p = NULL,*r = NULL;int j = 0;p = L;while(p->next != NULL && j < i-1) //p->next 第一個結點不為空{p = p->next;j++;}if (j != i-1){printf("刪除位置不合法!");return ERROR;}r = p->next;p->next = r->next;*e = r->data;free(r);r = NULL;return OK; }//求單鏈表的長度 //包括頭結點 int ListLength(LinkList L) {Node *p = NULL;int j = 0;p = L;//頭指針不為空,說明頭結點存在while(p != NULL){p = p->next;j++;}return j; }//用單鏈表求兩個集合的差集 /**求集合A-B即是求集合的差集,只需要把A和B集合中相同的,在A中刪除,A中剩余的*即是A和B的差集*/ void Difference(LinkList LA,LinkList LB) {//注:定義一個pre一個p指針變量,pre始終指向p的前驅,若p指向的值和B中某值相等,通過前驅刪除p指向的結點Node *pre = NULL,*p = NULL,*q = NULL,*r = NULL;pre = LA;p = LA->next;while(p != NULL){q = LB->next;//循環(huán)判斷A中當前的元素是否在B中有相等的值while(q != NULL && q->data != p->data){q = q->next;}//若q不為空,說明在B中有與A相等的值,刪除A中相等的這個值if (q != NULL){r = p;pre->next = p->next;p = p->next;free(r);}else{pre = p;p = p->next;}} } //單鏈表的遍歷 void TraverseList(LinkList L) {Node *r = L->next;printf("Linklist:");while(r != NULL){printf("%c", r->data);r = r->next;}printf("\n"); }int main() {int length = 0;Node *s = NULL;ElemType e;LinkList H = NULL; //建立頭指針LinkList H1 = NULL;InitList(&H); //初始化InitList(&H1);printf("Input first linklist:\n");CreateFromHead(H); //單鏈表頭插法TraverseList(H);printf("Input second linklist:\n");CreateFromTail(H1); //單鏈表尾插法TraverseList(H1);printf("Get element of first linklist:\n");s = Get(H,1);printf("Element:%c\n",s->data);s = NULL;//查找與key相等的結點//s = Locate(H,'c');//printf("獲取與‘c’相等值的結點:%c\n",s->data);//單鏈表的刪除printf("Delete element of first linklist:\n");DelList(H,3,&e);printf("Deleted element:%c\n",e);TraverseList(H);//單鏈表的插入操作printf("Insert an element:\n");InsList(H,2,'x');TraverseList(H);//求單鏈表的長度//注:計算單鏈表的長度的時候,頭結點也包含在內,算一個長度length = ListLength(H)-1;printf("length:%d\n",length);return 0; }?
單鏈表實現(xiàn)棧 Linkstack.c ?
#include <stdio.h> #include <stdlib.h>typedef struct Stackelemtype {int x;int y; }Stackelemtype;typedef struct Linknode {Stackelemtype data; //鏈棧的數據類型的定義,內含x和y. struct Linknode *next; }Linkstacknode;typedef Linkstacknode* Linkstack; //定義結點類型//簡單的初始化,在定義了結點類型后,置頭結點下一個結點為空 void Initlinkstack(Linkstack H) {H->next=NULL; }//入站操作,傳入x,y數據 int Push(Linkstack H,int x,int y) {Linkstacknode *temp=NULL;temp=(Linkstack)malloc(sizeof(Linkstacknode));if(!temp){printf("Memory is not enough!");return 0;}temp->data.x=x;temp->data.y=y;temp->next=H->next;H->next=temp;return 1; }//出棧操作,要返回x,y值傳遞不行,所以要返回地址 int Pop(Linkstack H,int *x,int *y) {Linkstacknode *temp=NULL;if(H->next!=NULL){temp=H->next;*x=temp->data.x;*y=temp->data.y;H->next=H->next->next;free(temp);temp=NULL;return 1;}else{return 0;} }//取棧頂元素,同理傳地址 int Get(Linkstack H,int *x,int *y) {if(H->next!=NULL){*x=H->next->data.x;*y=H->next->data.y;return 1;}else{return 0;} }int Isempty(Linkstack H) {if(H->next==NULL){return 1;}else{return 0;} }void Clear(Linkstack H) {Linkstacknode *temp=NULL;while(H->next!=NULL){temp=H->next->next;free(temp);temp=NULL;} }int main() {int i,c,a,b,x,y;Linkstacknode H;//H=(Linkstacknode *)malloc(sizeof(Linkstacknode));Initlinkstack(&H);printf("Input coordinate:\n");for(i=0;i<3;i++){scanf("%d %d",&x,&y);Push(&H,x,y);}a=Isempty(&H);printf("Is empty:%d\n",a);Get(&H,&x,&y);printf("Get first coordinate:\n");printf("%d %d\n",x,y);printf("Output Linkstack:\n");for(i=0;i<3;i++){Pop(&H,&x,&y);printf("%d %d\n",x,y);}Clear(&H);a=Isempty(&H);printf("Is empty:%d\n",a);return 0; }?
單鏈表實現(xiàn)隊列 Linkqueue.c
#include <stdio.h> #include <stdlib.h>typedef char Datatype;typedef struct Node {Datatype data;struct Node *next; }QueueNode;typedef struct Qnode {QueueNode *front;QueueNode *rear; }Linkqueue;void Initial(Linkqueue *Q) {Q->front=(QueueNode *)malloc(sizeof(QueueNode));Q->rear=(QueueNode *)malloc(sizeof(QueueNode));Q->front->next=NULL;Q->rear=NULL; }int Isempty(Linkqueue *Q) {return ((Q->front->next==NULL)&&(Q->rear==NULL)); }void Enterqueue(Linkqueue *Q,char x) {QueueNode *p=(QueueNode *)malloc(sizeof(QueueNode));p->data=x;p->next=NULL;if(Isempty(Q)){Q->front->next=p;Q->rear=p;}else{Q->rear->next=p;Q->rear=p;} }char Dequeue(Linkqueue *Q) {char x;QueueNode *p;p=(QueueNode *)malloc(sizeof(QueueNode));if(Isempty(Q)){printf("Empty!");exit(1);}p=Q->front->next;x=p->data;Q->front->next=p->next;if(Q->rear==p){Q->rear=Q->front;}free(p);return x; }char Front(Linkqueue *Q) {if(Isempty(Q)){printf("Empty!");exit(1);}return Q->front->next->data; }void Trav(Linkqueue *Q) {QueueNode *p;p=(QueueNode *)malloc(sizeof(QueueNode));p=Q->front->next;while(p!=NULL){printf("[%c]",p->data);p=p->next;} }int main() {Linkqueue Q;char a,b,first,sec;Initial(&Q);while(1){scanf("%c",&a);if(a=='~'){break;}else{Enterqueue(&Q,a);}}printf("Trav:");Trav(&Q);printf("\n");first=Front(&Q);printf("The first element is:[%c]\n",first);b=Dequeue(&Q);printf("Dequeue:[%c]\n",b);b=Dequeue(&Q);printf("Dequeue:[%c]\n",b);sec=Front(&Q);printf("The first element is:[%c]\n",sec);printf("Enter elements:");char c=getchar();while(1){scanf("%c",&a);if(a=='~'){break;}else{Enterqueue(&Q,a);}}printf("Trav:");Trav(&Q);printf("\n");return 0; }總結
以上是生活随笔為你收集整理的数据结构——线性表的链式表示的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构——绪论以及线性表的顺序表示
- 下一篇: 数据结构——排序算法(含动态图片)