单链表及基本操作(C语言)

#include <stdio.h>
#include <stdlib.h>

/**
* 含头节点单链表定义及基本操作 
*/

//基本操作函数用到的状态码 
#define TRUE 1;
#define FALSE 0;
#define OK 1;
#define ERROR 0;
#define INFEASIBLE -1;  //当不可行时 
const int OVERFLOW = -2;    //当溢出时 

//Status是新定义的一种函数返回值类型,其值为int型,意义为函数结果 状态码 
typedef int Status; 
//定义一种 数据元素 类型,为表示方便,定义为char型 
typedef char ElemType;
//单链表定义 
typedef struct Lnode {
    ElemType data;        //数据域,这里是char类型变量 
    struct Lnode *next;        //指针域,结构体类型指针 
} Lnode, *LinkList;
/**
* 注:方式 Lnode* p 和 LinkList L 定义出的指针p、L类型等价,
* 但一般用前者定义指向元素节点的指针,用后者定义指向链表的指针 
*/


//基本操作1:单链表初始化 
Status InitList(LinkList *list) {
    (*list)=(LinkList)malloc(sizeof(Lnode));
    (*list)->next=NULL;
    return OK;
}

//基本操作2:判断单链表是否为空
int IsEmpty(LinkList list) {
    if(list->next){
        return FALSE;
    } else {
        return TRUE;
    }
} 

//基本操作3:单链表销毁
Status DestroyList(LinkList *list) {
    Lnode *p; //工作指针
    while(*list){
        p=(*list);
        (*list)=(*list)->next;
        free(p);
    } 
    return OK;
}

//基本操作4:单链表清空 
Status ClearList(LinkList *list) {
    Lnode *p,*q;
    p=(*list)->next; 
    
    //清空结点 
    while(p){
        q=p->next;
        p=NULL;
        p=q;
    }
    
    //清空头结点 
    (*list)->next=NULL;
    return OK;
}

//基本操作5:求单链表长
int GetLength(LinkList list){
    Lnode *p;
    int len=0;
    p = list->next;  //p先指向首元结点 
    while(p){
        len++;
        p=p->next; 
    } 
    return len;
} 

//基本操作6:根据结点索引i获取相应位置元素的内容 
Status GetElem(LinkList list,int i,ElemType *elem) {
    Lnode *p;  //工作指针 
    int j=0;  //计数器 
    p=list->next;  //p指向第一个结点 
    while(p&&j<i){
        p=p->next;
        j++;
    } 
    /**
    *正常情况下此时:j=i(到达目标点,找到)或者p->NULL(到达表尾,仍未找到); 但若i<1,此时i<j=1,也未找到;
    */
    if(!p||i<j) return ERROR;
    *elem=p->data;
    return OK;
}

//基本操作7:查找与目标元素值相同的元素结点,返回元素地址 ,若不存在,返回NULL地址
Lnode* LocateElemAddress(LinkList list,ElemType elem) {
    Lnode *p;
    p=list->next;
    while(p&&p->data!=elem){
        p=p->next;
    }
    return p;
}

//基本操作8:查找与目标元素值相同的元素结点,返回逻辑索引(1~n),若不存在,返回0
int LocateElemIndex(LinkList list,ElemType elem) {
    Lnode *p;
    int j=1;
    p=list->next;
    while(p&&p->data!=elem) {
        j++;
        p=p->next;
    }
    if(p) return j;
    return 0;
}

//基本操作9:插入新元素数据到指定位置。(i为逻辑位置) 
Status ListInsert(LinkList *list,int i,ElemType elem){
    if(i<1) return ERROR; //插入位置序号小于1 
    Lnode *p;
    int j=0;  //计数器
    p=*list;
    //先找到第i-1个结点 
    while(p&&j<i-1){ 
        j++;
        p=p->next;
    } 
    //这里正常情况,j=i-1,p指向第i-1个结点;否则,j=表长+1,p->NULL 
    
    if(!p) return ERROR;
    
    //构造新结点 
    Lnode *new_node;
    new_node=(Lnode*)malloc(sizeof(Lnode));
    new_node->data= elem;
    //插入到链表 
    new_node->next=p->next;
    p->next=new_node;
    return OK;
} 

//基本操作10:删除链表第i个结点,被删除的结点数据保存在实参elem 
Status ListDelete(LinkList *list,int i,ElemType *elem) {
    Lnode *p,*q;
    int j=0;
    p=*list;
    while(p->next&&j<i-1){
        p=p->next;
        j++;
    }
    if(!(p->next)||j>i-1) return ERROR;  //删除位置不合理
    
    q=p->next; //q指向被删除的结点 
    
    //连接链表
    p->next=p->next->next;  //或者:p->next=q->next;
    
    //保存删除结点的数据
    *elem=q->data;
    
    //释放内存
    free(q);
    return OK;
}



//基本操作11:头插法建立链表,假设我们的数据保存在ElemType类型的数组中(且头结点已建立)。 
Status CreateList_H(LinkList *list,ElemType arrData[],int length) {
    int j;
    for(j=length-1;j>=0;j--){
        //新建结点 
        Lnode *node;
        node=(Lnode*)malloc(sizeof(Lnode));
        node->data=arrData[j];
        node->next=NULL;
        //插入为1号结点 
        node->next=(*list)->next;
        (*list)->next=node;
    }
    return OK;
}

//基本操作12:尾插法建立链表。 
Status CreateList_R(LinkList *list,ElemType arrData[],int length) {
    int j;
    Lnode *r;    //尾指针
    r=*list;
    for(j=0;j<length;j++) {
        Lnode *node;
        node=(Lnode*)malloc(sizeof(Lnode));
        node->data=arrData[j];
        node->next=NULL;
        
        r->next=node;  //node插入到表尾 
        r=node;  //r指向尾结点 
    }
    return OK; 
} 

//基本操作13:链表元素遍历输出  
Status ListTraverse(LinkList list) {
    Lnode *p;
    p=list;
    int j=0;
    printf("逻辑索引:    结点数据:\n");
    while(p->next){
        j++;
        p=p->next;
        printf(" %d          %c\n",j,p->data);
    }
    return OK;
}


int main(void){
    //定义一个链表(用指针list1表示一个链表) 
    LinkList list1;
    
    //链表初始化 
    Status initResultCode=InitList(&list1);
    printf("list1初始化结果:%d\n",initResultCode); 
    
    //给链表添加结点 (下面将用函数实现:头插法、尾插法) 
    //结点初始化
    Lnode *node1,*node2,*node3;
    node1=(Lnode*)malloc(sizeof(Lnode));
    node2=(Lnode*)malloc(sizeof(Lnode));
    node3=(Lnode*)malloc(sizeof(Lnode));
    node1->data='Y';
    node2->data='C';
    node3->data='L';
    node1->next=NULL;
    node2->next=NULL;
    node3->next=NULL;
    //结点连接 
    list1->next=node1;
    node1->next=node2;
    node2->next=node3;
    node3->next=NULL;
    //打印初始结点 
    printf("结点1的值:%c\n",list1->next->data); 
    printf("结点2的值:%c\n",list1->next->next->data); 
    printf("结点3的值:%c\n",list1->next->next->next->data); 
    
    
    //为空?
    /*
    int isNull=IsEmpty(list1); 
    printf("为空?:%d\n",isNull);
    */
    
    //销毁
    /*
    Status destroyResultCode = DestroyList(&list1); 
    printf("销毁结果状态码为:%d\n",destroyResultCode); //1 
    //测试 
    //printf("销毁后结点1的值:%c\n",list1->next->data); //Nothing
    */
    
    //清空
    /* 
    Status clearResultCode = ClearList(&list1);
    //测试 
    printf("清空结果状态码为%d\n",clearResultCode); //1 
    //printf("清空后结点1的值:%c\n",list1->next->data); //Nothing
    */ 
    
    
    //获得表长
    /*
    int listLength = GetLength(list1);
    printf("表长:%d\n",listLength); 
    */
    
    //用 中间元素elemx 保存索引到的元素的值
    /*
    ElemType elemx;
    Status getElemResult = GetElem(list1,3,&elemx);
    printf("得到元素?:%d\n",getElemResult);
    printf("得到元素值:%c\n",elemx);
    */
    
    
    //查找元素结点,返回元素地址
    /*
    ElemType elemTarget1='L';
    Lnode *address = LocateElemAddress(list1,elemTarget1); 
    printf("查找到元素的地址:0x%p\n",address);
    */
    
    
    //查找元素结点,返回元素逻辑索引
    /*
    ElemType elemTarget2='L';
    int index=LocateElemIndex(list1,elemTarget2);
    printf("查找到元素的索引:%d\n",index);
    */
    
    
    //插入
    /* 
    ElemType elemInserted='T';
    Status insertResultCode = ListInsert(&list1,2,elemInserted);
    printf("插入结果状态码:%d\n",insertResultCode);
    //遍历测试 
    ListTraverse(list1);
    */ 
    
    
    //删除结点,保存到删除的数据
    /*
    ElemType deletedElem;
    Status deleteResultCode=ListDelete(&list1,2,&deletedElem);
    printf("删除结果状态码:%d\n",deleteResultCode);
    printf("被删除结点的数据:%c\n",deletedElem);
    //遍历测试 
    ListTraverse(list1);
    */
    
    
    
    /**
    * 链表的建立:头插法、尾插法。 
    */ 
    //产生数据并保存到数组 
    ElemType data1='A',data2='B',data3='C',data4='D',data5='E',data6='F';
    ElemType waitInserted[]={
        data1,
        data2,
        data3,
        data4,
        data5,
        data6,
    };
    //获得数组长度 
    int arrLength=sizeof(waitInserted)/sizeof(waitInserted[0]);
    
    //头插法建立链表 
    /* 
    LinkList list2;        //定义新链表 
    InitList(&list2);    //链表初始化,建立头结点 
    //由数组数据建立链表 
    Status createListResult1 = CreateList_H(&list2,waitInserted,arrLength); 
    printf("建表结果状态码:%d\n",createListResult1);
    //遍历测试 
    ListTraverse(list2);
    */ 
    
    //尾插法建立链表 
    /*
    LinkList list3;        //定义新链表 
    InitList(&list3);    //链表初始化,建立头结点 
    //由数组数据建立链表 
    Status createListResult2 = CreateList_R(&list3,waitInserted,arrLength); 
    printf("建表结果状态码:%d\n",createListResult2);
    //遍历测试 
    ListTraverse(list3);
    */
    
    printf("\nEND!");
    return 0;
}

 

上一篇:Django(五)1 - 4章实战:从数据库读取图书列表并渲染出来、通过url传参urls.py path,re_path通过url传参设置、模板语法


下一篇:单链表的实现:带头节点和不带头节点