线性表的链式表示和实现

线性表的链式表示和实现

首先来看一下线性表的顺序存储和链式存储的区别
顺序存储结构 —— 可随机存储,但插入或删除需要移动大量元素
链式存储结构 —— 便于插入或删除,但不可随机存取(其实可以通过操作使其随机存取)

线性链表

以存储的数据为整型(int)为例:

头结点的定义:

typedef struct HNode{
    int length;
    char info[100];
    struct LNode *next;
}HNode;

注:大部分示例程序都直接用链表节点的类型来声明头节点,但我觉得应该为头节点定义单独的类型,也许这样会使操作变得略微麻烦,但也会带来很多好处。比如,当链表中的节点存储的数据为浮点型数组、字符型数组等类型的数据,而头结点是用整形来存储链表的长度的时候,分开定义更为合理。

链表节点的定义

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode;

1、创建空链表

HNode* createNullList()         /**创建空链表的函数的定义**/
{
    HNode* head;
    head=(HNode*)malloc(sizeof(HNode));
    head->length = 0;
    if(head!=NULL){
        head->next=NULL;
        printf("Has create null list success!\n");
    }
    else
        printf("Out of space!\n");
    return head;
}

2、判断链表是否为空

int isNullList(HNode *head)      /**判断是否链表是否为空的函数的定义(Y-1,N-0)**/
{
    return head->next==NULL;
}

3、在链表的结尾添加新节点

int append_t(HNode *head, int n)      /**在已存在的链表最后增加一个新结点的函数的定义(Y-1,N-0)**/
{
    LNode *p, *pnew;
    pnew=(LNode*)malloc(sizeof(LNode));
    if(pnew==NULL){
        printf("Out of space!\n");
        return 0;
    }
    else{
        pnew->data = n;
        p = head->next;                 /*p先指向头结点*/
        if(p == NULL){                  /*如果链表为空*/
            head->next = pnew;
            pnew->next = NULL;
        }
        else{
            while(p->next!=NULL)        /*若p所指不是链尾*/
                p=p->next;              /*p后移一个结点*/
            p->next=pnew;               /*链尾的next存储新结点指针*/
            pnew->next=NULL;            /*使新结点成为链尾*/
        }
        head->length++;
    }
    return 1;
}

4、由结点中的元素查找结点的位序

int locate(HNode *head, int n, LNode **p)  /**求某结点的指针,并返回其位序的函数的定义**/
{
    int i = 1;
    *p = NULL;
    *p = head->next;                   /*将头结点的next域赋值给p,使指向第一个结点*/
    while(*p != NULL && (*p)->data != n){
        i++;
        *p = (*p)->next;
    }
    if(*p == NULL)
        return 0;
    return i;
}

5、由某结点的指针查找该节点的前驱结点的指针

LNode* locatePre(HNode *head, LNode *p)   /**求p所指结点的前驱的函数的调用**/
{
    LNode *ptemp;
    ptemp = head->next;
    while(ptemp != NULL && ptemp->next != p)
        ptemp = ptemp->next;
    return ptemp;
}

6、在某结点之后插入一个新结点

int append_t(HNode *head, int n)      /**在已存在的链表最后增加一个新结点的函数的定义(Y-1,N-0)**/
{
    LNode *p, *pnew;
    pnew=(LNode*)malloc(sizeof(LNode));
    if(pnew==NULL){
        printf("Out of space!\n");
        return 0;
    }
    else{
        pnew->data = n;
        p = head->next;                 /*p先指向头结点*/
        if(p == NULL){                  /*如果链表为空*/
            head->next = pnew;
            pnew->next = NULL;
        }
        else{
            while(p->next!=NULL)        /*若p所指不是链尾*/
                p=p->next;              /*p后移一个结点*/
            p->next=pnew;               /*链尾的next存储新结点指针*/
            pnew->next=NULL;            /*使新结点成为链尾*/
        }
        head->length++;
    }
    return 1;
}

7、删除结点

int deletendnd(HNode *head, int i, int *e)           /**结点的删除函数的定义**/
{
    int j = 0;
    LNode *p, *q;
    p = head->next;
    if(i == 1){
        j = 1;
        head->next = p->next;
        *e = p->data;
        free(p);
        return 1;
    }
    while(p->next != NULL && j < i-2){
        p = p->next;
        j++;
    }
    if(!(p->next) || j > i-2)
        return 0;
    q = p->next;
    p->next = q->next;
    *e = q->data;
    free(q);
    head->length--;
    return 1;
}

————————————————————————————-

完整代码:

除了以上基本操作外,本代码又添加了一些其他功能,并且改善了交互性。
本代码的头结点与其余结点采用的是不同的数据类型,因此增加了代码的复杂性

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

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode;

typedef struct HNode{
    int length;
    char info[100];
    struct LNode *next;
}HNode;

HNode* createNullList();                /**创建空链表的函数的声明**/
int isNullList(HNode*);                 /**判断是否链表是否为空的函数的声明(Y-1,N-0)**/
int append_h(HNode*, int);                /**在已存在的链表最前增加一个新结点的函数的声明(Y-1,N-0)**/
int append_t(HNode*, int);                /**在已存在的链表最后增加一个新结点的函数的声明(Y-1,N-0)**/
int locate(HNode*, int, LNode**);              /**求某结点的指针并返回位序的函数的声明**/
LNode* locatePre(HNode*, LNode*);        /**求p所指结点的前驱的函数的声明**/
LNode* locfda(HNode*, int);             /**查找某位序的元素的数据的函数的声明**/
int insert(HNode*, LNode*, int);      /**在某结点之后插入一个新结点的函数的声明(Y-1,N-0)**/
int deletendndnd(HNode*, int);                 /**结点的删除函数的声明**/
int clear(HNode*);                      /**清空链表的函数的声明**/
int batchadd(HNode*, int, int*);                   /**批量添加结点的函数的声明**/
void reverse(HNode*);                   /**单链表的就地逆置函数的声明**/
void print_L(HNode*);
void print_hyphen(int);


/******************************************************************************************************************/

int main(void)
{
    int data;             /*结构体成员的数据*/
    LNode *p;

    print_hyphen(5);
    printf("单链表的操作示例");
    print_hyphen(5);
    printf("\n");

    HNode *head;
    if((head=createNullList()) != NULL)      /**创建空链表的函数的调用**/
    {
        char info[50];
        printf("请输入此链表的信息(50个字符以内):\n");
        gets(info);
        strcpy(head->info, "The example for CSDN!\n");
        strcpy(head->info + strlen("The example for CSDN!\n"), info);
    }
    else{
        exit(1);
    }

    int end = 0;
    while(!end){
        print_hyphen(15); printf("\n");
        printf("请输入指令来执行操作\n");
        print_hyphen(15); printf("\n");
        printf("1、判断链表是否为空\n2、在链表最前增加一个新结点\n3、在链表最后增加一个新结点\n4、查找某位序的元素的数据\n");
        printf("5、在某结点之后插入一个新结点\n6、删除某结点并返回其值\n7、查找某元素的位序\n8、清空链表\n");
        printf("9、求某结点的前驱\n10、查看链表信息\n11、批量添加结点\n12、显示链表长度\n13、查看链表数据\n14、逆置链表\n15、退出演示\n");
        print_hyphen(15); printf("\n");
        printf("输入要使用的功能的序号: ");
        int opt;
        scanf("%d",&opt);
        print_hyphen(15);
        printf("\n");
        switch(opt){
            case 1:
                if(isNullList(head))       /**判断是否链表是否为空的函数的调用(Y-1,N-0)**/
                    printf("链表为空!\n");
                else
                    printf("链表不为空!\n");
                break;

            case 2:
                printf("请输入要添加到链头的结点的数据: ");
                scanf("%d",&data);                   /**输入要添加的结点的数据*/
                if(append_h(head, data))           /**在已存在的链表最后增加一个新结点的函数的调用(Y-1,N-0)**/
                    printf("添加成功!\n");
                print_L(head);
                break;

            case 3:
                printf("请输入要添加到链尾的结点的数据: ");
                scanf("%d",&data);                   /**输入要添加的结点的数据*/
                if(append_t(head, data))           /**在已存在的链表最后增加一个新结点的函数的调用(Y-1,N-0)**/
                    printf("添加成功!\n");
                print_L(head);
                break;

            case 4:{
                int site;
                printf("请输入位序号: ");
                scanf("%d",&site);
                p = locfda(head, site);
                if(p != NULL)
                    printf("Has find the node!\n其数据为:%d\n", p->data);
                else
                    printf("Don't find the node!\n");
                break;
            }

            case 5:
                printf("请输入要求在其后插入新结点的结点的数据: ");
                scanf("%d",&data);
                locate(head, data, &p);
                int isinsert;
                printf("请输入新结点的数据: ");
                scanf("%d",&data);
                isinsert = insert(head, p, data);  /**在某结点之后插入一个新结点的函数的调用(Y-1,N-0)**/
                if(isinsert)
                    printf("插入成功!\n");
                else
                    printf("未插入成功!\n");
                print_L(head);
                break;

            case 6:
                printf("请输入要删除的结点的位序: ");
                int deletesi;
                scanf("%d",&deletesi);
                int deletend;
                if(deletendnd(head,deletesi,&deletend))             /**结点的删除函数的调用**/
                    printf("删除成功!\n其值为: %d\n", deletend);
                else
                    printf("未删除成功!\n");
                print_L(head);
                break;

            case 7:
                printf("请输入要寻找的结点的数据: ");
                int islocate;
                scanf("%d",&data);
                LNode *head_findnode;       /*要寻找的结构体的指针*/
                islocate = locate(head, data, &head_findnode);   /**求某结点的指针的函数的调用**/
                if(head_findnode != NULL)
                    printf("Has find the node!\n其位序为:%d\n", islocate);
                else
                    printf("Don't find the node!\n");
                break;

            case 8:
                if(clear(head))
                    printf("清空成功!\n");
                else
                    printf("清空失败!\n");
                break;

            case 9:
                printf("请输入要求前驱结点的结点的数据: ");
                scanf("%d",&data);
                LNode *prep;
                locate(head, data, &p);
                prep=locatePre(head,p);        /**求p所指结点的前驱的函数的调用**/
                if(prep==NULL)
                    printf("Don't find the prenode!\n");
                else
                    printf("Has find the prenode!The data is %d\n",prep->data);
                break;

            case 10:
                printf("%s\n", head->info);
                break;

            case 11:{
                int i;
                int batchnum;
                int batch[100];
                printf("请输入要批量添加的结点的个数: ");
                scanf("%d",&batchnum);
                printf("请输入各结点的数据(用空格隔开): ");
                for(i = 0; i < batchnum; i++)
                    scanf("%d", batch+i);
                if(batchadd(head, batchnum, batch))
                    printf("批量添加成功!\n");
                print_L(head);
                break;
            }

            case 12:
                printf("当前链表长度为: %d\n", head->length);
                break;

            case 13:
                print_L(head);
                break;

            case 14:
                reverse(head);
                printf("链表逆置后为:\n");
                print_L(head);
                break;

            case 15:
                print_hyphen(15);
                printf("\n");
                printf("再见!\n");
                print_hyphen(15);
                end = 1;
                break;

            default:
                print_hyphen(15);printf("\n");
                printf("无此序号,请重新输入!\n");
                print_hyphen(15);printf("\n");
        }

    }
    return 0;
}

/*********************************************************************************************************************/

HNode* createNullList()         /**创建空链表的函数的定义**/
{
    HNode* head;
    head=(HNode*)malloc(sizeof(HNode));
    head->length = 0;
    if(head!=NULL){
        head->next=NULL;
        printf("Has create null list success!\n");
    }
    else
        printf("Out of space!\n");
    return head;
}

int isNullList(HNode *head)      /**判断是否链表是否为空的函数的定义(Y-1,N-0)**/
{
    return head->next==NULL;
}

int append_h(HNode *head, int n)               /**在已存在的链表最前增加一个新结点的函数的定义(Y-1,N-0)**/
{
    LNode *p, *pnew;
    pnew = (LNode*)malloc(sizeof(LNode));
    if(pnew == NULL){
        printf("Out of space!\n");
        return 0;
    }
    pnew->data = n;
    pnew->next = head->next;
    head->next = pnew;
    head->length++;
    return 1;
}

int append_t(HNode *head, int n)      /**在已存在的链表最后增加一个新结点的函数的定义(Y-1,N-0)**/
{
    LNode *p, *pnew;
    pnew=(LNode*)malloc(sizeof(LNode));
    if(pnew==NULL){
        printf("Out of space!\n");
        return 0;
    }
    else{
        pnew->data = n;
        p = head->next;                 /*p先指向头结点*/
        if(p == NULL){                  /*如果链表为空*/
            head->next = pnew;
            pnew->next = NULL;
        }
        else{
            while(p->next!=NULL)        /*若p所指不是链尾*/
                p=p->next;              /*p后移一个结点*/
            p->next=pnew;               /*链尾的next存储新结点指针*/
            pnew->next=NULL;            /*使新结点成为链尾*/
        }
        head->length++;
    }
    return 1;
}

int locate(HNode *head, int n, LNode **p)  /**求某结点的指针,并返回其位序的函数的定义**/
{
    int i = 1;
    *p = NULL;
    *p = head->next;                   /*将头结点的next域赋值给p,使指向第一个结点*/
    while(*p != NULL && (*p)->data != n){
        i++;
        *p = (*p)->next;
    }
    if(*p == NULL)
        return 0;
    return i;
}

LNode* locatePre(HNode *head, LNode *p)   /**求p所指结点的前驱的函数的调用**/
{
    LNode *ptemp;
    ptemp = head->next;
    while(ptemp != NULL && ptemp->next != p)
        ptemp = ptemp->next;
    return ptemp;
}

LNode* locfda(HNode *head, int n)              /**查找某位序的元素的数据的函数的定义**/
{
    LNode *p = head->next;
    if(n < 1 || n > head->length)
        return NULL;
    while(n > 1 && p != NULL){
        p = p->next;
        n--;
    }
    if(n > 1)
        return NULL;
    else
        return p;
}

int insert(HNode *head, LNode *p, int n)  /**在某结点之后插入一个新结点的函数的定义(Y-1,N-0)**/
{
    LNode *pnew = (LNode*)malloc(sizeof(LNode));
    if(pnew == NULL){
        printf("Out of space!\n");
        return 0;
    }
    pnew->data = n;
    pnew->next = p->next;
    p->next = pnew;
    head->length++;
    return 1;
}

int batchadd(HNode *head, int n, int *s)                /**批量添加结点的函数的定义**/
{
    LNode *p, *pnew;
    int i;
    p = head->next;
    if(head->next == NULL){
        pnew=(LNode*)malloc(sizeof(LNode));
        if(pnew==NULL){
            printf("Out of space!\n");
            return 0;
        }
        pnew->data = s[0];
        head->next = pnew;
        pnew->next = NULL;
        p = pnew;
        head->length++;
        i = 1;
    }
    else{
        while(p->next != NULL)
            p = p->next;
        i = 0;
    }
    while(i < n){
        pnew=(LNode*)malloc(sizeof(LNode));
        if(pnew==NULL){
            printf("Out of space!\n");
            return 0;
        }
        pnew->data = s[i];
        pnew->next = NULL;
        p->next = pnew;
        p = pnew;
        i++;
        head->length++;
    }
    return 1;
}

int deletendnd(HNode *head, int i, int *e)           /**结点的删除函数的定义**/
{
    int j = 0;
    LNode *p, *q;
    p = head->next;
    if(i == 1){
        j = 1;
        head->next = p->next;
        *e = p->data;
        free(p);
        return 1;
    }
    while(p->next != NULL && j < i-2){
        p = p->next;
        j++;
    }
    if(!(p->next) || j > i-2)
        return 0;
    q = p->next;
    p->next = q->next;
    *e = q->data;
    free(q);
    head->length--;
    return 1;
}

int clear(HNode *head)
{
    LNode *pa, *pb;
    pa = pb = head->next;
    while(pa != NULL && pb != NULL){
        pb = pa->next;
        free(pa);
        pa = pb->next;
        free(pb);
    }
    return 1;
}

void reverse(HNode *head)                   /**单链表的就地逆置函数的定义**/
{
    LNode *p, *q;
    p = head->next;
    head->next = NULL;
    while(p != NULL){
        q = p;
        p = p->next;
        q->next = head->next;
        head->next = q;
    }
}

void print_L(HNode *head)
{
    printf("\n当前链表中的数据为:\n");
    LNode *p = head->next;
    while(p != NULL){
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

void print_hyphen(int n)
{
    while(n--)
        printf("-");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值