1、链表思想:每个节点都存储分为数据和地址两个方面。
数据是链表记录的内容,地址分为此节点的地址和它的前驱和后缀地址。
通过,每次通过地址来时先链表的遍历,查找,删除等操作。
2、链表分类
如果是单链表,就是只有后继,只能向后移动,因此,为了方便查找链表的某个节点,常常设置头结点。
双向链表:同时具有前驱和后缀,可以向前或者向后移动。
循环链表:最后的单元反过来,直至第一个单元,可以有表头,也可以是双向链表
3、链表的具体实现操作:
(1)单链表的实现
#include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> #define ERRROR -1 //链表的结构 typedef int ElementType; struct Node{ ElementType x; struct Node *next; }; typedef struct Node* List; typedef List Position; //链表的操作 List MakeEmpty(List L); int IsEmpty(List L); int IsLast(Position p,List L); Position Find(ElementType x,List L); void Delete(ElementType x,List L); Position FindPrevious(ElementType x,List L); void Insert(ElementType x,List L,Position p); void DeleteList(List L); //测试是否为空表 int IsEmpty(List L) { return L->next==NULL; } //测试是否为最后一个节点 int IsLast(Position p,List L) { return p->next==NULL; } //初始化 List Init(List L) { L = (List)malloc(sizeof(struct Node)); if(L==NULL) { printf("Out of Space! "); } else L->next=NULL; return L; } //查找函数 Position Find(ElementType x,List L) { List p=L; while(p!=NULL&&p->x!=x) { p=p->next; } return p; } //删除链表 void Delete(ElementType x,List L) { List tp,p; p=FindPrevious(x,L); if(!IsLast(p,L)) { tp=p->next; p->next=tp->next; free(tp); } } //查找前一个元素 Position FindPrevious(ElementType x,List L) { Position p=L; while(p->next!=NULL&&p->next->x!=x) { p=p->next; } return p; } //插入 void Insert(ElementType x,List L,Position p) { List tp; tp=(List)malloc(sizeof(struct Node)); if(tp==NULL) { printf("Out of Space!!! "); } tp->x=x; tp->next=p->next; p->next=tp; } //删除 void DeleteList(List L) { List p,tp; tp=L->next; L->next=NULL; while(tp!=NULL) { p=tp->next; free(tp); tp=p; } } void Print(List L) { List p=L->next; while(p!=NULL) { printf("%d ",p->x); p=p->next; } printf(" "); } int main(void) { List L,p; L=Init(L); p=L; int i,x,n; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x); Insert(x,L,p); p=p->next; } Print(L); printf("将7插入3的前面: "); p=FindPrevious(3,L); Insert(7,L,p); Print(L); printf("删除4: "); Delete(4,L); Print(L); return 0; }
(2)双向链表
#include<stdio.h> #include<stdlib.h> #include<string.h> struct Node{ int data; struct Node *Pre,*Rear; }; typedef struct Node* DoList; DoList Init(DoList L) //初始化 { L=(DoList)malloc(sizeof(struct Node)); L->Pre=NULL; L->Rear=NULL; return L; } int IsEmpty(DoList L) //判断是否为空 { if(L->Pre==NULL&&L->Rear==NULL) return 1; return 0; } int IsLast(DoList L,DoList p) //判断最后一个元素 { if(p->Pre!=NULL&&p->Rear==NULL) return 1; return 0; } DoList FindPrevious(int x,DoList L) //找到前一个元素 { DoList p=L; while(p->Rear!=NULL&&p->Rear->data!=x) { p=p->Rear; } return p; } void Insert(int x,DoList L,DoList p) //插入某个元素 { DoList tp=(DoList)malloc(sizeof(struct Node)); if(tp==NULL) { printf("Out of Space!!! "); } //printf("%d ",x); tp->data=x; //先前再后 tp->Pre=p; tp->Rear=p->Rear; if(p->Rear==NULL) p->Rear=tp; //这里要注意,因为可能存在p->Rear==NULL的情况。 else { p->Rear->Pre=tp; p->Rear=tp; } } void Delete(int x,DoList L) //删除某个元素 { DoList p,tp; p=FindPrevious(x,L); tp=p->Rear; p->Rear=tp->Rear; tp->Rear->Pre=p; free(tp); } void Print(DoList L) //正序输出 { DoList p=L->Rear; while(p!=NULL) { printf("%d ",p->data); p=p->Rear; } printf(" "); } void RePrint(DoList L) //逆序输出 { DoList p,tp; p=L->Rear; while(!IsLast(L,p)) p=p->Rear; while(p->Pre!=NULL) { printf("%d ",p->data); p=p->Pre; } printf(" "); } void DeleteList(DoList L) //输出链表 { DoList p,tp; p=L->Rear; L->Rear=NULL; while(p!=NULL) { tp=p->Rear; free(p); p=tp; } } int main(void) { DoList L,p; L=Init(L); p=L; int n,x,i; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x); Insert(x,L,p); p=p->Rear; } Print(L); p=FindPrevious(3,L); Insert(7,L,p); //DeleteList(L); RePrint(L); return 0; }
(3)循环链表
循环单链表
#include<stdio.h> #include<stdlib.h> #include<string.h> struct Node{ int data; struct Node *next; }; typedef struct Node* CyList; CyList Init(CyList L) { L=(CyList)malloc(sizeof(struct Node)); L->data=-1; L->next=L; return L; } int Empty(CyList L) { return L->next==L; } CyList FindPrevious(int x,CyList L) { CyList p=L; while(p->next->data!=x&&p->next!=NULL) { p=p->next; } return p; } void Insert(int x,CyList L,CyList p) { CyList tp=(CyList)malloc(sizeof(struct Node)); tp->data=x; tp->next=p->next; p->next=tp; } void Delete(int x,CyList L) { CyList p,tp; p=FindPrevious(x,L); if(p->next!=NULL) { tp=p->next; p->next=tp->next; delete tp; } } void Print(CyList L) { CyList p=L->next; while(p!=L) { printf("%d ",p->data); p=p->next; } printf(" "); } void DeleteList(CyList L) { CyList p,tp; p=L->next; L->next=L; while(p!=L) { tp=p->next; delete p; p=tp; } } void DoPrint(CyList L) { CyList p=L->next; int tim=0; while(1) { if(tim==1&&p==L) break; if(p==L&&tim==0) { p=p->next; tim=1;continue; } printf("%d ",p->data); p=p->next; } } int main(void) { CyList L,p; L=Init(L); p=L; int n,i,x; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x); Insert(x,L,p); p=p->next; } p->next=L; Print(L); p=FindPrevious(3,L); Insert(7,L,p); Print(L); Delete(2,L); Print(L); DoPrint(L); return 0; }
循环双向链表
#include<stdio.h> #include<stdlib.h> #include<string.h> struct Node{ int data; struct Node *Pre,*Rear; }; typedef struct Node* DuList; DuList Init(DuList L) { L=(DuList)malloc(sizeof(struct Node)); L->Pre=L; L->Rear=L; return L; } int IsEmpty(DuList L) { if(L->Pre==L&&L->Rear==L) return true; return false; } void Insert(int x,DuList L,DuList p) { DuList tp=(DuList)malloc(sizeof(struct Node)); tp->data=x; tp->Pre=p; tp->Rear=p->Rear; p->Rear->Pre=tp; p->Rear=tp; } DuList FindPrevious(int x,DuList L) { DuList p=L; while(p->data!=x) p=p->Rear; return p->Pre; } void Delete(int x,DuList L) { DuList p,tp; p=FindPrevious(x,L); tp=p->Rear; p->Rear=tp->Rear; tp->Rear->Pre=p; } void Print(DuList L) { DuList p=L; printf("%d ",p->data); p=p->Rear; while(p!=L) { printf("%d ",p->data); p=p->Rear; } printf(" "); } void DeleteList(DuList L) { DuList p=L->Rear,tp=L; delete tp; L=NULL; while(p!=NULL) { tp=p->Rear; delete tp; p=tp; } } int main(void) { int n,x,i; DuList p,L; scanf("%d",&n); scanf("%d",&x); p=Init(p); p->data=x; L=p; for(i=1;i<n;i++) { scanf("%d",&x); Insert(x,L,p); p=p->Rear; } Print(L); Delete(3,L); Print(L); p=FindPrevious(2,L); Insert(7,L,p); Print(L); return 0; }
注意:1、如果对p->next进行操作,p一定不能为空,否则会出问题。
2、双向链表中的插入操作,先对tp的前驱操作,再对tp的后驱操作。
3、循环链表的最大特征就是首尾相连,空表时,自己指向自己(指的是单链表的头结点,如果是双向链表,直接让第一个节点的前驱指向最后一个节点,
最后一个节点的后驱指向第一个节点就行了)。
书后练习:
3.2:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> struct Node{ int id,data; struct Node* next; }; typedef struct Node* List; List Init(List L) { L=(List)malloc(sizeof(struct Node)); L->next=NULL; return L; } void Insert(int x,List L,List p) { List tp=(List)malloc(sizeof(struct Node)); tp->data=x; if(tp==NULL) { printf("Out of Space!!! "); } tp->next=p->next; p->next=tp; } int FindNum(List L,int pos) { List tp,p=L->next; int i=1; while(p!=NULL&&i!=pos) { i++;p=p->next; } return p->data; } void PrintLots(List L,List p) { List tp=p->next; while(tp!=NULL) { printf("%d ",FindNum(L,tp->data)); tp=tp->next; } printf(" "); } void Print(List L) { List p=L->next; while(p!=NULL) { printf("%d ",p->data); p=p->next; } printf(" "); } int main(void) { int begintime=0,endtime; List L1,p,L2; L1=Init(L1); L2=Init(L2); p=L1; int n,x,i; printf("创建L序列: "); scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x); Insert(x,L1,p); p=p->next; } Print(L1); printf("创建P序列: "); p=L2; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&x); Insert(x,L2,p); p=p->next; } Print(L2); PrintLots(L1,L2); endtime=clock(); printf("程序运行时间为:%dmm ",endtime-begintime); return 0; }