带头结点的单链表的常用操作(C语言版)

/*
    带头结点的单链表的常用操作

    说明:本版本在 main 函数里加入了 InitFlag 变量,用以识别传递的实参链表未初始化时的野指针问题。正常的操作时,这种情况应尽量避免,本版本没有刻意在操作里增加参数 InitFlag,目的是让操作更纯粹一些。在操作里加入,则操作的参数合法性审核会更健壮。根据需要选择吧。

    1、链队初始化,初始化一个只含头结点的空单链表 L
        Status InitList_L (LinkList &L) ;
    2、构造单链表结点
        LNode* MakeNode_L(ElemType e); 
    3、销毁单链表
        Status DestroyList_L(LinkList &L)    ;
    4、判断单链表是否为空
        Status ListEmpty_L(LinkList L);
    5、清空单链表
        Status ClearList_L(LinkList &L);
    6、单链表的插入 P 的后继结点操作
        Status InsertAfter_L(LNode *p, LNode *q);
    7、头插法往单链表中的插入一个结点
        Status InsertFirst_L(LinkList &L, ElemType e);
    8、删除单链表的第 i 个结点
        Status ListDelete(LinkList &L,int i,ElemType &e);
    9、单链表的查找元素操作
        LNode* Search_L(LinkList L, ElemType e);
    10、在有序单链表中查找插入位置 
        LNode* SearchPosition_L(LinkList L, ElemType e);
    11、在有序表中的正确位置插入结点 e
        Status InsertNode_L(LinkList &L, ElemType e);
    12、求链表的长度
        Status GetListLength_L(LinkList L);
    13、遍历单链表
        Status ListTraverse_L(LinkList L, Status(*visit)(ElemType e));
    14、配合遍历,依次输出表中元素 
        Status PrintList_L(ElemType e);
    15、读取单链表中指定位置的元素
        Status GetPosElem_L(LinkList L, int pos, ElemType &e); 

*/

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

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define PERROR -2
typedef int Status;

// 数据元素的类型,使用时需根据问题的需求定义。
typedef int ElemType;

// 结单链表点类型定义
typedef struct LNode {
    ElemType data;    // 数据域
    struct LNode *next;    // 指针域
} LNode;

// 链表结构体类型定义
typedef  LNode*  LinkList;

// 1、链队初始化,初始化一个只含头结点的空单链表 L
Status InitList_L (LinkList &L) {
    L = (LNode*)malloc(sizeof(struct LNode));         // 为头结点申请空间
    if(L == NULL)    return  OVERFLOW;                  //如果申请失败,返回溢出
    L->next = NULL;
    return OK;
}
// 2、构造单链表结点
LNode* MakeNode_L(ElemType e) {
    LNode *p;
    p = (LNode*)malloc(sizeof(struct LNode)); // 分配结点空间
    if (p!=NULL) {
        p->data = e;
        p->next = NULL;
    }
    return p;
}

// 3、销毁单链表
Status DestroyList_L(LinkList &L){
    LNode *q; 
    if(L==NULL) return ERROR;        // 判断链表是否存在,已销毁,不再执行销毁操作。 
    while(L!=NULL) {                // 如果是非空表,依次释放表中各结点         
        q = L;
        L = q->next;
        free(q);
    }
    return OK;
}


// 4、判断单链表是否为空
Status ListEmpty_L(LinkList L){
    if(NULL == L) return ERROR;        // 判断链表是否存在,已销毁,不再执行销毁操作。
    if(L->next == NULL){
        return TRUE;
    }
    else{
        return FALSE;
    }
}

// 5、清空单链表 
Status ClearList_L(LinkList &L){
    if( L==NULL )return PERROR;    // 参数合法性检验,非法返回参数错误
    L->next = NULL;                // 将头结点的指针域置空 
    return OK;
}

// 6、单链表的插入 P 的后继结点操作
Status InsertAfter_L(LNode *p, LNode *q){
    if(p == NULL || q == NULL) return PERROR;  // 参数不合理
    q->next = p->next;                        // 修改q结点的指针域
    p->next = q;
    return OK;
}

// 7、头插法往单链表中的插入一个结点
Status InsertFirst_L(LinkList &L, ElemType e){
    if(L == NULL) return PERROR;              // 参数不合理
    LNode *p;
    p = MakeNode_L(e); 
    if(p == NULL)return ERROR;                // 内存溢出,结点创建不成功,不能执行插入操作
    p->next = L->next;                        // 修改q结点的指针域
    L->next = p;
    return OK;
}

// 8、删除单链表的第 i 个结点
Status ListDelete(LinkList &L,int i,ElemType &e){
    LNode *p, *q;
    p = L;
    int j = 0;
    while(p!=NULL && j<i-1){                    // 如果存在,找到第 i-1 个结点
        p = p->next;
        j++;
    }
    if(p==NULL||p->next==NULL)return ERROR;        // 如果第 i-1 个结点和第 i 个结点不存在,无法删除,返回错误 
    q = p->next;                                  // 用指针 q 指向第 i 个结点
    e = q->data;                                  // 将第 i 个结点的值赋给 e
    p->next = q->next;                          // 将 q 的后继赋值给 p
    free(q);                                    // 释放结点 q 所占空间 
    return OK;
}

// 9、单链表的查找元素操作
LNode* Search_L(LinkList L, ElemType e) {
    LNode *p;
    if(L == NULL) return NULL;
    p = L->next;
    while(p!=NULL && p->data != e) {
        p = p->next;   // 访问下一个元素
    }
    return  p;
}

// 10、在有序单链表中查找插入位置 
LNode* SearchPosition_L(LinkList L, ElemType e) {
    LNode *p, *q;
    if(L == NULL) return NULL;
    p = L;                    // p 用来保存插入位置的前一个结点 
    q = p->next;                // q 指向插入点对应的结点,即在插入点之前插入 e     
    while(q!=NULL && q->data<e) {
        p = q;                 // 寻找向后继续进行,p、q 均向后移动 
        q = p->next;           // 访问下一个元素
    }
    return  p;
}
// 11、在有序表中的正确位置插入结点 e
Status InsertNode_L(LinkList &L, ElemType e){
    if(L == NULL) return PERROR;              // 参数不合理
    LNode *p, *q;
    q = MakeNode_L(e);     
    if(p = NULL)return ERROR;                // 内存溢出,结点创建不成功,不能执行插入操作
    p = SearchPosition_L(L, e);
    q->next = p->next;                        // 修改q结点的指针域
    p->next = q;
    return OK;
}

// 12、求链表的长度
Status GetListLength_L(LinkList L) {
    int length = 0;
    LNode *p;
    if(L == NULL) return PERROR;              // 参数不合理
    if(L->next == NULL)return 0;
    p = L->next;
    while(p!=NULL){
        length++;
        p = p->next;
    }
    return length;
}

// 13、遍历单链表
Status ListTraverse_L(LinkList L, Status(*visit)(ElemType e))  {
    if(L == NULL) return PERROR;                  // 参数不合理
    if(L->next == NULL)return ERROR;              // 空表不执行操作 
    LNode *p;
    p = L->next;
    while (p != NULL) {
        visit(p->data);
        p = p->next;
    }
    return OK;
}
// 14、配合遍历,依次输出表中元素 
Status PrintList_L(ElemType e){
    printf("%d\t",e);
    return OK;
}
// 15、读取单链表中指定位置的元素
Status GetPosElem_L(LinkList L, int pos, ElemType &e){
    if(L == NULL) return PERROR;                  // 参数不合理
    if(L->next == NULL)return ERROR;              // 空表不执行操作
    if(pos<=0) return PERROR;                  // 参数不合理
    int i = 1;
    LNode *p;
    p = L->next;
    while(i!=pos){
        if(p->next == NULL) return ERROR;    // 指定位置超出了单链表的长度
        p = p->next;
        i++;    
    }
    e = p->data;
    return OK; 

 
int main(){
    int i, e, state;
    int InitFlag = FALSE;
    LinkList L;
    printf("1.初始化单链表\n");
    printf("2.销毁单链表\n");
    printf("3.判断单链表是否为空\n");
    printf("4.清空单链表\n");
    printf("5.将元素插入在表头\n");
    printf("6.从线性表中删除表头元素\n");
    printf("7.打印线性表中的所有元素\n");
    do{
        printf("请输入你要进行的操作:\n");
        scanf("%d",&i);
        switch(i){
            case 1 :
                    state = InitList_L(L);
                    if(state == OK){
                        InitFlag = TRUE;
                        printf("单链表初始化成功。\n");
                    }else{
                        printf("单链表初始化失败!\n"); 
                    }
                    break;
            case 2 :
                    if(InitFlag == FALSE){
                        printf("单链表不存在或已被销毁!\n");
                    }else{
                        state = DestroyList_L(L);
                        if(state == ERROR){
                            printf("请确认参数合法化或者先执行单链表的初始化操作!\n"); 
                        }else{
                            InitFlag = FALSE;
                            printf("单链表销毁成功。\n"); 
                        }
                    }
                    break;
                    
            case 3 :
                    if(InitFlag == FALSE){
                        printf("单链表不存在或已被销毁!\n");
                    }else{
                        state = ListEmpty_L(L);
                        if(state == PERROR){
                            printf("请确认参数合法化或者先执行单链表的初始化操作!\n"); 
                        }else if(state == TRUE){
                            printf("单链表为空!\n"); 
                        }else if(state == FALSE){
                            printf("单链表不为空!\n"); 
                        }
                    }
                    break;
                    
            case 4 :
                    if(InitFlag == FALSE){
                        printf("单链表不存在或已被销毁!\n");
                    }else{
                        state = ClearList_L(L);
                        if(state == PERROR){
                            printf("请确认参数合法化或者先执行单链表的初始化操作!\n"); 
                        }else{
                            printf("已为您清空单链表。\n");
                        }
                    }
                    break;
            case 5 :
                    if(InitFlag == FALSE){
                        printf("单链表不存在或已被销毁!\n");
                    }else{
                        printf("请输入将要利用头插法加入单链表的元素的值:\n");
                        scanf("%d",&e);
                        state = InsertFirst_L(L, e);
                        if(state == PERROR){
                            printf("请确认参数合法化或者先执行单链表的初始化操作!\n"); 
                        }else if(state == OK){
                            printf("元素 %d 成功加入单链表。\n",e); 
                        }else{
                            printf("元素 %d 加入单链表失败!\n",e); 
                        }
                    }
                    break; 
            case 6 :
                    if(InitFlag == FALSE){
                        printf("单链表不存在或已被销毁!\n");
                    }else{
                    state =  ListDelete( L, 1, e);
                        if(state == PERROR){
                            printf("请确认参数合法化或者先执行单链表的初始化操作!\n"); 
                        }else if(state == OK){
                            printf("表头元素 %d 成功从单链表里删除!\n",e); 
                        }else{
                            printf("单链表中没有元素,不能执行删除元素操作!\n");
                        }
                    }
                    break;
            case 7 :
                    if(InitFlag == FALSE){
                        printf("单链表不存在或已被销毁!\n");
                    }else{
                        state = ListTraverse_L(L, PrintList_L);
                        if(state == PERROR){
                            printf("请确认参数合法化或者先执行单链表的初始化操作!\n"); 
                        }else if(state == OK){
                            printf("链表中的元素已成功输出。\n"); 
                        }else{
                            printf("单链表中没有元素!\n");
                        }
                    }
                    break;
        }
    }while(i>=1&&i<=7);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tangguofeng/article/details/143046235