typedef struct LNode
{
int data; //数据域
struct LNode *next; //指针域
}LNode, *Linklist;
// LNode, 结构体类型名,描述链表中的结点类型
// LinkList ,结构体指针类型名,用来说明“单链表类型的”变量
//基础知识::小细节
// LNode *p; LinkList L;
// p 为单链表结点的指针(p指向结点),
// L 标记一具体的单链表。。
int Init_List ( LinkList &L ) {
//L是带头结点的单链表的头指针
// L = new LNode;这样也行,虽然申请的是结构体,但是返回是个指针类型
L=(Linklist)malloc(sizeof(LNode)) //申请头结点
if(!L) exit(-2);
L->next=NULL;
return 1;
}
int ListEmpty(Linklist L){
if(L->next){
return 0;
}else {
return 1;
}
}
int ClearList(Linklist &L)
{
Linklist p,q;
p = L->next;//指向头结点
while(p)
{
q = p->next;
free(p);
p = q;
}
return OK;
}
int ListLength(Linklist L){
Linklist p;
p=L->next;
int j=0;
while(p){
j++;
p=p->next;
}
return j;
}
int GetElem(Linklist L,int i, int &e)
{
Linklist p= L; //定义临时指针p:外指
int k = 0;
while(p && k< i-1) //第i个的前一个
{
p = p->next;
k++;
}
if(!p || k> i-1)
{
return ERROR;
}
e = p->next->data;
return OK;
}
int LocateElem(Linklist L,int e){
Linklist p=L->next;
int j=1;
while(p&&p->data!=e){
p=p->next;
j++;
}
if(p)return j;
else return 0;
}
这个是带有头结点的:
int ListInsert(Linklist &L,int i,int e)
{
int j = 1;
Linklist p = L;
while( p && j < i) //找到j=i,temp是目标结点的前一个结点
{
p = p->next;
j++;
}
if(!p || j > i)
{
return ERROR;
}
Linklist q = (Linklist)malloc(sizeof(Node));//动态申请内存,链表的意义(随时扩容)
q->data = e;
q->next = p->next;
p->next = q;
return OK;
}
这个是不带有头结点的:
Status ListInsert( LinkList &L, int i, ElemType e ) {
// L是不带头结点的单链表,在ai之前插入新结点e
if(i<=0) return ERROR; //i太小,非法
if(i==1){s=new Lnode; s->data=e; s->next=L; L=s;}
else {
p=L; j=0; //p指向头结点,j是计数器
while(p && j<i-1){p=p->next; j++;} //令p指向ai-1
if(!p) return ERROR; //i太大,非法
s=new Lnode;s->data=e;
s->next=p->next; p->next=s; } //修改指针
return OK;
}
int ListDelete(Listlink &L,int i,int &e)
{
int j = 1;
Linklist p = L;
while( p && j < i) //找到要删除的前一结点
{
p = p ->next;
j++;
}
if(!p || j > i)
{
return ERROR;
}
Linklist q = p->next; //要删除的结点
e = q->data;
p->next = q ->next;
free(q);
return OK;
}
int ListLength ( LinkList L ) {
// L是带头结点的单链表
Linklist p=L->next;
int n=0;
while(p) {
n++;
p=p->next;
}
return (n);
}
void CreatList1( LinkList &L,int n ) {
//逆位序输入n个元素的值,建立带结点的单链表L
L=new LNode; //申请头结点
L->next=NULL;
for(int i=n;i>0;i--){
s=(LNode*)malloc(sizeof(LNode)); //申请新结点
scanf(&e); //从键盘输入一个元素值
s->data=e;
s->next=L->next;
L->next=s; //插入链表
} // for
}
void CreateList2( LinkList &L,int n ) {
//从键盘正序输入n个元素值,按尾插法创建带头结点的单链表L
L=new LNode; L->next=NULL; //定义头结点
r=L; //r是L的尾指针
for(int i=n;i>0;i--){
scanf(&e); //从键盘输入一个元素值
s=new LNode; //申请新结点
s->data=e;
s->next=NULL;
r->next=s; //将s插入链表尾
r=s; //修改尾指针
} // for
}
void Union(Linklist &La, Linklist &Lb){
La_len=ListLength(La);
char e;
while(!EmptyList(Lb)){
ListDelete(Lb,1,e);
if(!LocateElem(La,e)){
ListInsert(La,++La_len,e);
}
}
Destory(Lb);
}
void Intersect(Linklist &La, Linklist &Lb){
int i=1;
int e;
while(i<=ListLength(La)){
GetElem(La, i, e);
if(!LocateElem(Lb, e)) {ListDelete(La, i, e);}
else i++;
}
Destroy(Lb); //销毁Lb
}
bool isequal( Linklist La, Linklist Lb) { //判断集合La和Lb是否相等
int La_len=ListLength(La); //求La表长
int Lb_len=ListLength(Lb);//求Lb表长
if(La_len!=Lb_len) {return FALSE;}
Linklist Lc;
InitList (Lc); //初始化Lc
for(int i=1;i<=La_len;i++){ //建立La的副本Lc
GetElem(La, i, ai);
ListInsert(Lc,i,ai);
}
bool found=TRUE; //辅助变量found用来作为查找标志
for(int k=1;k<=Lb_len && found; k++){
GetElem(Lb, k, e); //读取Lb中第k个元素e
i=LocateElem(Lc,e);
if(i==0) found=FALSE; //e在Lc中不存在,改标志
else ListDelete(Lc,i,e); //存在,Lc中删除e
} //for
DestroyList(Lc);
return found;
}
void MergeList ( List La, List Lb, List &Lc) {
//将有序线性表La和Lb归并成有序线性表Lc
int i = j = 1;
int k=0;
InitList (Lc); //初始化
int La_len=ListLength(La);Lb_len=ListLength(Lb);//求表长
while (i<=La_len && j<=Lb_len) { //La和Lb均非空
GetElem(La, i, ai); GetElem(Lb, j, bj);//读ai和bj
if(ai<=bj){ListInsert(Lc, ++k, ai ); i++;}
else {ListInsert(Lc, ++k, bj); j++;}
}
while(i<=La_len){ //La中剩余元素一一插入Lc
GetElem(La,i++,ai); ListInsert(Lc, ++k, ai);}
while(j<=Lb_len){ //Lb中剩余元素一一插入Lc
GetElem(Lb,j++, bj); ListInsert(Lc, ++k, bj);}
}
第一种方法:
void ReverseLinkList1 ( LinkList &L ) {
// L是带头结点的单链表。用头插法逆置L
p=L->next; //p指向a1
L->next=NULL; //剥离头结点
while (p) { q=p->next ; //用辅助指针q“拽住”p的后继
p->next=L->next ; L->next=p ;
//将当前待插入链表中的首结点*p插入L中,成为L的首结点
p=q ; //p,q后移
} // while
}
第二种
//方法2:将所有结点的next指针逆转
void ReverseLinkList2 ( LinkList &L ) {
// L是带头结点的单链表的头指针;p、q、r是三个辅助指针
//在扫描链表的过程中进行逆置操作
if ( !L->next ) return; //空表
p=L->next; q=p->next; //原表中,*p为*q的前驱
p->next=NULL; //a1的next置空指针,剥离头结点
while (q) { r=q->next ; //修改q->next之前,保存q->next到r
q->next=p ; //逆置表中,*q为*p的前驱
p=q ; q=r ; //参与扫描的指针都需后移
}
L->next=p;
}
对循环链表的操作与普通单链表基本相同,只是判表空和判断表尾元素的条件有所不同:
判断表尾:p->next == head
判断表空:head->next == head
typedef struct DuLNode {
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
} DuLNode, *DuLinkList;
DuLNode — 双向链表的结点类型
DuLinkList — 双向链表类型
//----------------约瑟夫环的实现-----------------------
int ImplementList(LinkList &L,int m)
{
if(L==NULL)
{
printf("人数为空,出列结束");
return FALSE;
}
LinkList p=L;
printf("密码为: %d ", m);
while(p->next!=L) // 到第一个的前面
p=p->next;
for(int n=Listsize(L); n>0 ; n--)
{
for(int i=1; i<=m-1; i++){
p=p->next; // 一直往下,然后找到目标的前面;
}
m=p->next->data;
printf(" 出列编号为:%d \n", p->next->number);
printf("密码为: %d ", p->next->data);
LinkList q=p->next;
p->next=q->next;
free(q);
}
return OK;
}