線性表有n(n>=0)個類型相同的數據節點組成的有限序列。數組
《a1,a2,a3.....an》函數
線性表是典型的的線性結構,表中數據元素有序且有限。
其特色可概括爲同一性,又窮性,有序性。指針
根據結構不一樣分爲 順序表,連接表 兩種。code
1.順序表:將同類型節點安邏輯順序一次存入一組連續的存儲單元中。blog
順序表的邏輯順序與物理順序一致,即,在物理內存中排列順序是相鄰連續的。內存
以一位數組爲例,其結構以下:get
| a1 | a2 | a3 | a4 | ......... | a(n-2) | a(n-1) | an |it
如下是順序表的使用:io
#include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 typedef int ElemType; // 定義節點結構體 typedef struct { ElemType elem[MAXSIZE]; int last; }SeqList; // 初始化線性表 SeqList *InitList( ) { SeqList *p; p=(SeqList *)malloc(sizeof(SeqList)); p->last = -1; return p; } // 根據元素的值,獲取表中元素位置 int Locate(SeqList *L, ElemType e) { int i; for (i=0;i<=L->last;i++) if (L->elem[i]==e) return i+1; return -1; } // 根據指定位置,獲取節點的值 ElemType GetData(SeqList *L,int i) { if(i<=L->last+1) return L->elem[i-1]; else printf("%d is wrong\n",i); } void main() { int i; SeqList *p; p=InitList( ); printf("%d\n",p->last); //顯示-1 for(i=0;i<10;i++) p->elem[i]=i+50; //50,51,52,53。。。59 p->last=i-1; //9寫入last,表示最後一個元素下標 i=Locate(p,53); //返回4 printf("%d\n",i); printf("%d\n",GetData(p,5)); //顯示54 }
2.鏈表:用一組任意存儲單元,來存儲線性表中的數據元素。在物理內存中的位置沒有固定順序,可零散分佈在任意位置上。
每一個節點除存儲數據以外,還要存儲相鄰單元的地址信息。即:節點由 數據域 指針域兩部分組成。ast
從連接方式上可分爲:單鏈表、雙鏈表、環表
從實現角度上可分爲:動態鏈表、靜態鏈表
單鏈表:每一個節點的指針域只包含一個指針,第一個節點無前驅稱爲鏈表頭,整個鏈表經過鏈表頭獲取。最後一個節點無後驅,稱爲鏈表尾,指針域爲空。有些時候未使用方便,也會在第一個節點以前單獨掛一個頭結點,用於存放鏈表長度等數據,頭結點的next指針指向第一個節點。
單列表代碼演示:
#include "stdio.h" #include "stdlib.h" #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 20 typedef int Status; typedef int ElemType; // 定義鏈表節點 typedef struct Node { ElemType data; struct Node *next; }Node; // 初始化鏈表,爲鏈表頭分配空間 typedef struct Node *LinkList; int InitList(LinkList *L) { *L=(LinkList)malloc(sizeof(Node)); /* 產生頭結點,並使L指向此頭結點 */ if(!(*L)) /* 存儲分配失敗 */ return ERROR; (*L)->next=NULL; /* 指針域爲空 */ return OK; } // 獲取鏈表長度 /* 初始條件:順序線性表L已存在。操做結果:返回L中數據元素個數 */ int ListLength(LinkList L) { int i=0; LinkList p=L->next; /* p指向第一個結點 */ while(p) { i++; p=p->next; } return i; } void CreateFromTail(LinkList L) { Node *r, *s; char c; int flag =1; //設置一個標誌,當輸入"$"時,flag爲0,建表結束 r=L; //r指向鏈表的當前表尾,其初值指向頭結點 while(flag) //循環輸入表中元素值,將創建新結點s插入表尾*/ { c=getchar(); if(c!='$') { s=(Node*)malloc(sizeof(Node)); s->data=c; r->next=s; r=s; } else { flag=0; r->next=NULL; //最後一個結點的next置爲空,表示鏈表結束 } } } int main() { LinkList L; int i; if(InitList(&L)) //指針的地址 printf("鏈表L初始化完畢,ListLength(L)=%d\n",ListLength(L)); CreateFromTail(L); printf("鏈表L初始化完畢,ListLength(L)=%d\n",ListLength(L)); }
環表:是鏈表的首尾相接,尾巴節點的next指針指向頭指針,造成環狀順序結構
其操做與普通鏈表操做相似。
雙向鏈表:與單鏈表不一樣之處在與每一個節點指針域除了指向後驅節點的的next指針以外,還有指向前驅節點的prior節點。這樣方便雙向操做,可減小運算複雜度。
(p->prior)->next == p == (p->next)->prior;
操做雙向鏈表代碼
#include <stdio.h> //雙向非循環鏈表 #include <stdlib.h> #define ElemType int #define ERROR -1 #define OK 1 typedef struct DNode { ElemType data; struct DNode *prior,*next; }DNode,*DoubleList; int DlinkIns(DoubleList L,int i,ElemType e) { DNode *s,*p; //在p結點以前插入s結點 int k; p=L; k=0; //從「頭」開始,查找第i個結點,至關於頭結點是0號結點 while(p->next!=L&&k<i) //找到尾節點沒找到跳出或k==i跳出 { p=p->next; k=k+1; } if(p->next==L&&k!=i) //插入位置不合理,i的值不合適此鏈表 { printf("插入位置不合理!"); return ERROR;} s=(DNode*)malloc(sizeof(DNode)); //p已就位,開始申請s結點空間 if (s) //s空間申請成功 { s->data=e; p->prior->next=s; //創建左邊關係 s->prior=p->prior; p->prior=s; //創建右邊關係 s->next=p; return OK; } else return ERROR; } void Init_DLinklist(DoubleList *H) //LinkList爲指針型 { *H=(DoubleList)malloc(sizeof(DNode)); //申請一個結點空間 (*H)->next=*H; (*H)->prior=*H; } void Creat_DLinkList(DoubleList L) { char c; static int i=1; DoubleList s; printf("請輸入第%d個結點的值",i); scanf("%d",&c); if(c!=-1){ s=(DNode*)malloc(sizeof(DNode)); s->data=c; L->next=s; s->prior=L; L->prior=s; s->next=L; } printf("請輸入第%d個結點的值",i+1); scanf("%d",&c); while(c!=-1) //輸入-1結束 { DlinkIns(L,1,c); //在第一個結點以前插入,頭插法 i++; printf("請輸入第%d個結點的值",i+1); scanf("%d",&c); } } void Print_DLinkList(DoubleList L) { DoubleList p=L->next; while(p!=L) {printf("%8d",p->data); p=p->next; } } int DlinkDel(DoubleList L,int i,ElemType *e) //doublelinkdelete { DNode *p; //p指向要刪除的結點 int k; p=L; k=0; //從「頭」開始,查找第i個結點,頭結點至關於第0個結點 while(p->next!=L && k<i) //找第i個結點 { p=p->next; k=k+1; } if(p->next==L&&k<i) return ERROR; //到尾結點也未找到i結點,i太大 else { *e=p->data; //被刪除結點的值由e指針帶回給主調函數 p->next->prior=p->prior; p->prior->next=p->next; free(p); } } int main(int argc, char *argv[]) { int i,e; DoubleList DL; Init_DLinklist(&DL); Creat_DLinkList(DL); Print_DLinkList(DL); printf("\n請輸入要刪除結點的序號:"); scanf("%d",&i); DlinkDel(DL,i,&e); Print_DLinkList(DL); printf("\n要刪除的結點的值爲:%d",e); return 0; }