数据结构-链表

采用链式存储结构的线性表称为线性链表。结点包含数据域和指针域两部分。链表明指向第一个结点(头指针),尾结点指针域值为NULL。

定义的辅助宏:

#define OK 1
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define NULL 0
#define OVERFLOW -1
typedef  int ElemType;//假设链表中的元素均为整型
typedef int Status;

链表的存储结构定义

//链表的存储结构定义
typedef struct LNode{
    ElemType data;                   //数据域
    struct LNode * next;             //指针域
}LNode,*LinkList;

初始化L为一个空的有序链表:

Status InitList_L(LinkList &L) {
	//初始化L为一个空的有序链表
    L=(LNode *)malloc(sizeof(LNode));
    if(L==NULL)
        exit(OVERFLOW); 
    L->next=NULL;
    return OK;
}

在链表L的第i个位置前插入元素e,i的合法值为1..L.length

Status ListInsert_L(LinkList &L,int i,ElemType e){
   //在链表L的第i个位置前插入元素e,i的合法值为1..L.length
   //定位到第i-1个结点,在其后插入一个新开辟的结点,注意i异常。
   LNode *p=L;                                //p始终指向第j个结点
   int j=0;
   while(p&&j<i-1) {//T(n)=O(n);              只要不空且味道第i-1个
     p=p->next;
     j++;
   }
   if(!p||i<1)//插入位置不合法,第i-1个结点不存在或者i<1
       return ERROR;
   LNode *q;
   q=(LNode *)malloc(sizeof(LNode));
   if(!q)
       exit(OVERFLOW);
   q->data=e;
   q->next=p->next;
   p->next=q;
   return OK;
}

依次输出有序链表L中的各个元素.

void OutputElem(ElemType e){
    printf("%d\n",e);
}


void ListPrint_L(LinkList &L){
	 //依次输出有序链表L中的各个元素
    if(L->next==NULL)
        printf("空表");
    else{
	LNode *p=L->next;
	while(p){ //T(n)=O(n);
	    OutputElem(p->data);
	    p=p->next;
        } 
    }
}

销毁有序链表L.

Status DestroyList_L(LinkList &L){
    //销毁有序链表L
    LNode *p=L,*q;
    while(p){
        q=p->next;
	free(p);
	p=q; 
    } 
    return OK;
}

链表置空.

Status ClearList_L(LinkList &L){
    //链表置空
   LNode *p=L->next,*q;   
   while(p){
       q=p->next;
       free(p);
       p=q;
   }
   L->next=NULL;
   return OK;
}

用e带回L中第i个元素的值并返回OK,i介于1与L.length之间,否则返回ERROR.

Status GetElem_L(LinkList &L,int i,ElemType &e){
//用e带回L中第i个元素的值并返回OK,i介于1与L.length之间,否则返回ERROR
//L为带头结点的单链表的头指针。第i个元素存在时,设遍历指针与相应计数器,
//从头开始后移至计数器为i停。i异常
    LNode *p=L;                             //p指向第0个元素结点,j是该结点的位序
    int j=0; 
    while(p&&j<i){                          //顺序查找。只要p不空且未到第i结点就前进                          
        p=p->next;
	j++;
    }
    if(i<1||!p)                              //第i个结点不存在或者i<1
	return ERROR;
    e=p->data;                               //取第i个元素
    return OK;
}

更新第i个元素结点的值为e,若i不合法则返回ERROR.

Status PutElem_L(LinkList &L,int i,ElemType e){
	//更新第i个元素结点的值为e,若i不合法则返回ERROR
    LNode *p=L;
    int j=0;
    while(p&&j<i){
        p=p->next;
	j++;
    }
    if(i<1||!p)
	return ERROR;
    p->data=e;
    return OK;
}

删除L中第i个元素并用e带回,i介于1与表长之间.

Status ListDelete_L(LinkList &L,int i,ElemType &e){
    //删除L中第i个元素并用e带回,i介于1与表长之间
    //寻找第i-1个结点,若其后继结点存在则带回其data并删除
    LNode *p=L,*q;            //p始终指向第j个结点
    int j=0;
    while(p&&j<i-1){          //寻找第i-1个结点
        p=p->next;
	j++;
    }                         //j最终为i-1,除非p空
    if(i<1||!(p->next)||!p)   //第i个或更前结点不存在
        return ERROR; 
    q=p->next;
    p->next=q->next;
    e=q->data;
    free(q);
    return OK;
}

判断表空

bool ListEmpty_L(LinkList &L){
    //判断表空
    LNode *p=L;
    if(!p->next)
        return TRUE;
    return FALSE;
}

返回表长.

int ListLength_L(LinkList &L){
    //返回表长
    int i=0;
    LNode *p=L;
    while(p->next){
       p=p->next;
       i++;
    }
    return i;
}

返回L中第一个与元素e满足关系cmp()的元素的位序,若不存在则返回0.

Status compare(ElemType e1,ElemType e2){
    return e1==e2;
}

int LocateElem_L(LinkList &L,ElemType e,Status (*compare)(ElemType,ElemType)){
//返回L中第一个与元素e满足关系cmp()的元素的位序,若不存在则返回0
    int i=0;
    LNode *p=L->next;
    while(p){
      	i++;
        if(compare(p->data,e))
            return i;
        p=p->next;
    }
    return 0;
}

若cur_e是L中的元素且不是第一个,就返回他的前驱,否则pre_e未定义 操作失败.

Status PriorElem_L(LinkList &L,ElemType cur_e,ElemType &pre_e){
	//求前驱
    LNode *p=L;
    int i=0;
    while(p->next){
        if(p->next->data==cur_e&&i!=0){
           pre_e=p->data;
           return OK;
        }
    i++;
    p=p->next;
    }
    return ERROR;
}

若cur_e是L中的元素且不是最后一个,就返回他的后驱,否则pre_e未定义 操作失败.

Status NextElem_L(LinkList &L,ElemType cur_e,ElemType &pre_e){
	//求后驱
    LNode *p=L->next;
    while(p){
        if(p->data==cur_e&&p->next)	{
           pre_e=p->next->data;
           return OK;
	}
    p=p->next;
    }
    return ERROR;
}

对每个数据调用visit()。

Status ListTraverse_L(LinkList &L,int (*visit)(ElemType &)){
    //对每个数据调用visit()
    LNode *p=L->next;
    while(p){
       visit(p->data);
       p=p->next;
    }
    return OK;
}

逆位序创建n个结点链表.

void IntputElem(ElemType &e) {
    scanf("%d",&e);
}


Status CreatList_L(LinkList &L,int n){
    //逆位序创建n个结点链表
    //开辟头结点并初始化。循环n次,每次新开辟一个结点放到头后
    L=(LNode *)malloc(sizeof(LNode));
    if(!L)
       exit(OVERFLOW);
    L->next=NULL;
    LNode *p;
    for(int i=0;i<n;i++){
       p=(LNode *)malloc(sizeof(LNode));
       IntputElem(p->data);
       p->next=L->next;
       L->next=p;
    }
    return OK;
}

删除大于mink小于maxk的值.

void ListPartDel_Sorted(LinkList &L,ElemType mink,ElemType maxk){
    //删除大于mink小于maxk的值
    //首先定位第一个大于等于mink的元素,循环{从其开始删除,直到遇到大于
    //maxk的停止}
    //preq最初指向头结点 p最初指向第一个元素结点,后文中preq始终指向p的前驱
    LNode *p=L->next,*prep=L;
    while(p&&p->data<mink)	{
        prep=prep->next;
	p=p->next;
    }//移动指针使指向第一个符合条件元素
    //说明链表元素均小于mink
    if(!p)
        return;
    while(p&&p->data<=maxk){ //移动指针判断是否符合条件,是就删除
        prep->next=p->next;
        free(p);
        p=prep->next;
    }
}

实现有头结点的链表的就地逆置.

Status ListInverse(LinkList &L){
    //实现有头结点的链表的就地逆置
    //令指针p指向首源节点,头结点与元素结点断开,用指针变量
    //p一次遍历各个元素结点,每次都将当前元素结点放到头结点的后面
    LNode *p=L->next,*q;
    L->next=NULL;
    while(p) {                  //把第一个结点后的结点依次插入到第一个位置,即可实现逆置
        q=p->next;              //令q指向p的后继结点,以便以后p后移
        p->next=L->next;        //接下来两句将p所指向结点插入到头结点后
        L->next=p;
        p=q;                    //q后移
    }
    return OK;
}

递归遍历每个数据:

void ListTraverse(LinkList L){
    //递归遍历每个数据:
   if(!L->next)
      return;
   else {
       printf("%d\n",L->next->data);
       ListTraverse(L->next);
   }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值