- 单链表的类型定义
typedef int TypeDate; //定义TypeDate为int型 typedef struct linknode { DateType date; //定义结点的数据域 struct linknode *next; //定义结点的指针域 }linklist;
上面定义的LinkList是结点类型,如果想定义一个指向该节点类型的指针head,c++中的语言如下:
LinkList *head;
如果想动态申请一个节点空间,并让指针head指向该结点空间,语句如下:
head=(LinkList *)malloc(sizeof(LinkList));
这样,head指针就指向该节点了,则这个结点的数据域为head->date或是(*head ).date,而指针域为head->next或(*head ).next.
- 单链表的初始化:单链表的初始化即构造一个仅包含头结点的空单链表。其过程是首先申请一个结点并让指针head指向该结点,然后将他的指针域赋为空,最后返回头指针head。其算法描述如下:
LinkList *InitList() { LinkList *head; head=(LinkList *)malloc(sizeof(LinkList)); //动态分配一个节点空间 head->next=NULL; return head; //头结点指针域为空,表示空链表 }
- 单链表的建立:头插法建表。链表与顺序表不同,它是一种动态管理的储存结构,链表中的每个结点占用的储存空间不是预先分配的,而是运行时根据系统需求生成的。因此,建立在初始化链表后,建立线性链表从空表开始,每读入一个有效数据则申请一个结点s,并将读取到的数据存放在新结点s的数据域中,然后将新节点插入到当前链表head的表头上,直到循环结束为止。
void CreateList (LinkList *head ,int n) { LinkList *s; int i; cout<<"请输入"<<n<<"个整数"<<endl; for(i=0;i<n;i++) { s=(LinkList *)malloc(sizeof(LinkList)); //生成新结点 cin>>s->date; //读入新节点数据域 s->next=head->next; //将头结点的指针域存入新结点的指针域 head->next=s; //头插法的具体表现,将新结点的地址存入头结点的 // 指针域 } cout<<"链表插入成功!"<<ednl; }
- 尾插法建表:头插法建表虽然算法简单容易理解,但生成的链表中结点的次序和原来输入的次序相反。而尾插法建立链表可实现次序的一致,该算法依旧从空表开始,但需增加一个尾指针last,使其指向当前链表的尾结点。其过程是:每读入有效的数据则申请一个结点s,并将新结点插入到当前链表尾部(last指针所指的结点后面),直到循环结束为止。
void CreateListL (LinkList *head,int n) { LinkList *s,*last; int i; last=head; //开始时last指向头结点 cout<<"请输入"<<n<<"个数:"<<endl; for(i=0;i<n;i++) { s=(LinkList *)malloc(sizeof (LinkList)); cin>>s->date; s->next=NULL; last->next=s; //last指针域指向新结点,即将新结点插入表尾 last=s; //s为新的表尾 } cout<<"线性表建立成功!"<<endl; }
- 求表长操作:因为链表是链式结构,所以链表中元素个数不是已知的。想求表中元素个数还得设一个计算变量j,将一个指针p先指向链表中第一个元素,当p不为空时,循环将p指针向后移,j+1,循环结束后j值即为链表长度。
int LengthList(LinkList *head ) { LinkList *L=head->next; int j=0; while(L!=NULL) { j++; p=p->next; } return j; }
- 查找操作:按值查找:从链表中第一个元素结点开始,由前向后依次比较单链表中各结点数据域中的值,某结点数据域中的值与给定的值x相等,则循环结束:否则继续向后比较直到表结束,然后判断指针p,若p不为空表示单链表中有x结点,输出查找成功的信息并输出x所在表中的位置;否则输出查找失败的信息。
void Locate(LinkList *head, DateType x) { int j=1; LinkList *p; p=head->next; while(p!=NULL && p->date!=x) { p=p->next; j++; } if(p!=NULL) cout<<"在链表中第"<<j<<"个位置找到了值为"<<x<<"的结点!"<<endl; else cout<<"链表不存在值为"<<x<<"的结点!"<<endl; }
- 插入操作:在指针所指的结点后插入新结点。若要在链表中指针p所指位置后面插入一个结点,则插入操作步骤如下:1.先将结点s的指针域指向结点p的下一个结点(s->next=p->next); 2.再将结点p的指针域改为指向新结点s(p->next=s).
void InsList(LinkList *head,int i,DateType x) { int j=1; LinkList *s,*p; p=head; while(p->next!=NULL && j<i-1) { p=p->next; j++; } if(p!=NULL) { s=(LinkList *)malloc(sizeof(LinkList)); s->date=x; s->next=p->next; p->next=s; cout<<"插入元素成功!"<<endl; } else cout<<"插入元素失败!"<<endl; }
-
删除操作:删除操作实现首先通过循环定位求出第i结点的前驱结点(第i+1结点)p的地址,然后将指针s指向被删除的结点,修改p->next指针,使其指向s后的结点,最后释放指针s所指结点。
void DelList(LinkList *head,int i) { itn j=1; DateType x; LinkList *p=head,*s; while(j<i-1 && p->next!=NULL) { p=p->next; j++; } if(j==i-1 && p->next!=NULL) { s=p->next; x=s->date; p->next=s->next; free(s);//释放所删除结点的空间 cout<<"删除第"<<i<<"个位置上的元素"<<x<<",成功!"<<endl; } else cout<<"删除失败!"<<endl; }
-
单链表的输出操作:即扫描单链表,输出各元素的值。
void PriList(LinkList *head) { LinkList *L=head->next; while(L->next!=NULL) { cout<<L->date<<" "; L=L->next; } cout<<endl; }
注意,通过上面的链表基本操作可知:
-
在单链表插入,删除一个结点,必须知道他的前驱结点;
-
单链表不具备按序号随机访问的特点,只能从头指针开始一个个顺序进行。