一:线性表:链表的初始化操作及应用

内容

    • 节点结构
    • InitList(*L):初始化一个线性表
    • ListEmpty(L):判断是否为空表
    • ClearList(*L):清空线性表
    • ListLength(*L):链表的表长
    • GetElem(L,i,*e):将表中的第i个元素,返回给e
    • LocateElem(L,e):查找表中e相等元素序号
    • ListInsert(L,i,e):在线性表的第i个位置插入元素e
    • ListDelete(*L,i,*e):删除线性表中的第i个元素,并将值返回给e
    • ListLength(L): 返回线性表元素的个数
    • 头插法插入元素创建链表
    • 尾插法插入元素创建链表
    • 求两个线性表La和Lb的并集
    • 求两个线性表La和Lb的交集
    • 判断两个集合La Lb是否相等
    • 合并有序的算法实现:
    • 逆置单链表
    • 循环链表
    • 双向链表
    • 约瑟夫环核心

节点结构

typedef struct LNode
{
	int  data;			//数据域
	struct LNode *next;		//指针域
}LNode, *Linklist;
// LNode, 结构体类型名,描述链表中的结点类型
// LinkList ,结构体指针类型名,用来说明“单链表类型的”变量
//基础知识::小细节
// LNode *p; LinkList L;
// p 为单链表结点的指针(p指向结点),
// L 标记一具体的单链表。。

InitList(*L):初始化一个线性表

int Init_List ( LinkList  &L ) {
       //L是带头结点的单链表的头指针
       // L = new LNode;这样也行,虽然申请的是结构体,但是返回是个指针类型
	L=(Linklist)malloc(sizeof(LNode))  //申请头结点
	if(!L) exit(-2);
	L->next=NULL;
	return 1;
}

ListEmpty(L):判断是否为空表

int ListEmpty(Linklist L){
    if(L->next){
        return 0;
    }else {
        return 1;
    }
}

ClearList(*L):清空线性表

int ClearList(Linklist &L)
{
	Linklist p,q;
	p = L->next;//指向头结点
	while(p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	return OK;
}

ListLength(*L):链表的表长

int ListLength(Linklist L){
    Linklist p;
    p=L->next;
    int j=0;
    while(p){
        j++;
        p=p->next;
    }
    return j;
}

GetElem(L,i,*e):将表中的第i个元素,返回给e

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;
}

LocateElem(L,e):查找表中e相等元素序号

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;
}

ListInsert(L,i,e):在线性表的第i个位置插入元素e

这个是带有头结点的:

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;
}

ListDelete(*L,i,*e):删除线性表中的第i个元素,并将值返回给e

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;
}

ListLength(L): 返回线性表元素的个数

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
}

求两个线性表La和Lb的并集

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);
}

求两个线性表La和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
}

判断两个集合La 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;
}

你可能感兴趣的:(#,大二上数据结构,链表,数据结构)