C语言实现数据机构链表的基本操作(从键盘输入生成链表、读取数组生成链表)

 

利用头插法实现逆置

下面简单介绍一下,算法思想结合图示看

算法思想:“删除”头结点与链表其他结点的原有联系(即将头结点的指针置空),再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的头结点,如此循环,直至原链表为空。

这是鬼话,看不懂可以不看,看下面就行......

void NiList(LinkList &L)    //逆置
{
    LinkList p = L->next, q;    //L->next是头结点的指针,p指针指向了首结点
    L->next = NULL;    //将头结点的指针置空
    while (p != NULL)
    {
        q = p;    //指针q从指向第一个结点开始后移
        p = p->next;    //指针p从指向第二个结点开始后移
        q->next = L->next;    //指针q所指向结点的指针q->next指向其上一个结点
        L->next = q;    //头结点的指针后移
    }
}

接下来,进行图解:

 

刚开始是这样

L->next是头结点指针。循环前的操作,p指向首结点(即第一个结点),头结点的指针置空

 

 

进入循环,q和p分别指向第一个和第二个节点

q所指向结点的指针q->next指向其(q->next)上一个结点,这里上一个结点的指针为空,故q->next也为空

L->next = q;    //头指针后移,指向首结点
 


 进入第二轮循环,这是发生重大变化的关键时期

 

q和p继续后移,这个图有点错误懒得改了,就是后移后,指针q指向了b结点,指针p指向了c结点

q所指向结点的指针q->next指向其上一个结点

头指针后移,指向第二个结点

你可以看到此时已经开始逆置,如此循环, 直到p==NULL为空

 

 

链表完整代码: 

1):从键盘输入生成链表

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

#define OK              1
#define ERROR           0
#define INFEASIBLE        -1
#define OVERFLOW        -2
#define TRUE            1
#define FALSE            0

typedef int Status;
typedef int ElemType;
typedef struct LNode
{
    ElemType data;
    struct LNode* next;
}LNode,*LinkList;
/*定义了两种新的数据类型LNode和LinkList,显然各个结点是LNode类型的,
头指针和结点的next成员是LinkList类型的,L是LinkList这个新的结构体指针类型定义的头指针*/

Status InitList(LinkList &L)    //初始化
{
    L = (LinkList)malloc(sizeof(LNode));
    if (L == NULL)return ERROR;
    L->next = NULL;
    return OK;
}

Status ListEmpty(LinkList L)    //判空
{
    if (L->next == NULL) return TRUE;
    return FALSE;
}

Status ListInsert(LinkList &L, int i, ElemType e)    //插入
{
    int j = 0;
    LinkList p = L, s;    //指针p指向头指针
    if (i<1) return ERROR;
    while ((p != NULL) && (j<i - 1))
    {
        p = p->next;
        j++;
    }
    if(p==NULL)return ERROR;
    s = (LNode*)malloc(sizeof(LNode));    //生成新节点
    if (s == NULL) return ERROR;
    s->data = e;    //s结点暂存e
    s->next = p->next;    //s结点的指针s->next指向第i个结点
    p->next = s;    //第i-1个结点的指针p->next指向s结点
    return OK;
}

Status ScanfList(LinkList &L)    //键盘输入
{
    ElemType e;
    int i = 1;
    printf("输入整数,以0结束:\n");
    scanf("%d", &e);
    while (e != 0)
    {
        if (!ListInsert(L, i, e)) return ERROR;
        i++;
        scanf("%d", &e);
    }
    return OK;
}

Status ListDelete(LinkList &L, int i, ElemType &e)    //删除
{
    int j = 0;
    LinkList p = L, q;
    if ((i<1) || (L->next == NULL)) return ERROR;
    while ((p != NULL) && (j<i - 1))
    {
        p = p->next;
        j++;
    }
    if (p == NULL) return ERROR;
    q = p->next;    //指针q暂存被删结点(第i个结点)的地址
    p->next = q->next;    //指针p(即第i-1个结点的指针)指向被删结点(第i+1个结点)
    e = q->data; 
    free(q);
    return OK;
}

Status GetElem(LinkList L, int i, ElemType &e)    //取值
{
    int j = 1;
    LinkList p = L->next;
    if (i<1) return ERROR;
    while ((p != NULL) && (j<i))
    {
        p = p->next;
        j++;
    }
    if (p == NULL) return ERROR;
    e = p->data;
    return OK;
}

int LocateElem(LinkList L, ElemType e)    //定位
{
    int j = 1;
    LinkList p = L->next;
    while (p != NULL)
    {
        if (p->data == e)return j;
        p = p->next;
        j++;
    }
    return j;
}

Status PriorElem(LinkList L, ElemType e, ElemType &pr_e)    //直接前驱
{
    LinkList p = L->next;
    if (p->data == e) return ERROR;    //首结点没有直接前驱
    while (p != NULL)
    {
        if (p->next->data == e) break;
        p = p->next;
    }
    if (p == NULL) return ERROR;    //指针p一直移到尾结点仍找不到e,返回错误
    pr_e = p->data;
    return OK;
}

int GetLength(LinkList L)    //求长度
{
    int i = 0;
    LinkList p = L;
    while (p->next != NULL)
    {
        p = p->next;
        i++;
    }
    return i;
}

void PrnList(LinkList L)    //遍历
{
    LinkList p = L->next;
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

void NiList(LinkList &L)    //逆置
{
    LinkList p = L->next, q;    //p指针指向了首结点
    L->next = NULL;    //将头结点的指针置空
    while (p != NULL)
    {
        q = p;    //指针q从指向第一个结点开始后移
        p = p->next;    //指针p从指向第二个结点开始后移
        q->next = L->next;    //指针q所指向结点的指针q->next指向其上一个结点
        L->next = q;    //头结点的指针后移
    }
}

Status Destroy(LinkList &L)    //销毁,从首结点开始
{
    LinkList p = L->next, q;
    while (p != NULL)
    {
        q = p->next;
        free(p);
        p = q;
    }
    free(L);
    return OK;
}


int main()
{
    int i;
    ElemType e, e1;

    LinkList L;
    if (InitList(L)) printf("OK\n");
    ScanfList(L);
    PrnList(L);

    int k;
    printf("\n1.插入\n2:删除\n3:取值\n4:定位\n5:直接前驱\n");
    printf("6.求长度\n7:遍历\n8:逆置\n9:销毁\n\n0.退出\n");
    scanf("%d", &k);
    while (k != 0)
    {
        switch (k)
        {
        case 1:
            printf("在第几个位置插入何数:");
            scanf("%d%d", &i, &e);
            if (ListInsert(L, i, e)) printf("OK\n");
            break;
        case 2:
            printf("删除第几个数:");
            scanf("%d", &i);
            if (ListDelete(L, i, e))printf("删除数为:%d\n", e);
            break;
        case 3:
            printf("获取第几个数:");
            scanf("%d", &i);
            if (GetElem(L, i, e)) printf("数为:%d\n", e);
            break;
        case 4:
            printf("定位何数:");
            scanf("%d", &e);
            if (LocateElem(L, e)) printf("位序为:%d\n", LocateElem(L, e));
            break;
        case 5:
            printf("寻找何数直接前驱:");
            scanf("%d", &e);
            if (PriorElem(L, e, e1)) printf("前驱为:%d\n", e1);
            break;
        case 6:
            printf("表长为:");
            printf("%d\n", GetLength(L));
            break;
        case 7:
            printf("遍历:\n");
            PrnList(L);
            break;
        case 8:
            NiList(L);
            PrnList(L);
            printf("逆置成功\n");
            break;
        case 9:
            if (Destroy(L))printf("销毁成功\n");
            break;
        default:
            printf("ERROR\n");
        }
        scanf("%d", &k);
    }
    return 0;
}
View Code

 

2):读取数组生成链表

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

#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0

typedef int Status;
typedef int ElemType;
typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode, *LinkList;
/*定义了两种新的数据类型LNode和LinkList,显然各个结点是LNode类型的,
头指针和结点的next成员是LinkList类型的,L是LinkList结点指针类型定义的头指针*/

Status InitList(LinkList &L)    //初始化
{
    L = (LinkList)malloc(sizeof(LNode));
    if (L == NULL)return ERROR;
    L->next = NULL;
    return OK;
}

Status ListEmpty(LinkList L)    //判空
{
    if (L->next == NULL)return ERROR;
    else return FALSE;
}

Status ListInsert(LinkList &L, int i, ElemType e)    //插入
{
    int j = 0;
    LinkList p = L, s;    //指针p指向头指针
    if (i < 1)return ERROR;
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }
    if (p == NULL)return ERROR;
    s = (LNode*)malloc(sizeof(LNode));    //生成新节点
    if (s == NULL)return ERROR;
    s->data = e;    //结点s暂存e
    s->next = p->next;    //s结点的指针s->next指向第i个结点
    p->next = s;    //指针p指向s结点
    return OK;
}

Status CreateList(LinkList &L,ElemType element[], int n)    //数组生成链表
{
    int i;
    for (i = 0; i < n; i++)
        if (!ListInsert(L, i + 1, element[i])) return ERROR;
    return OK;
}

Status ListDelete(LinkList &L, int i, ElemType &e)    //删除
{
    int j = 0;
    LinkList p = L, q;
    if (i < 1 || p->next == NULL)return ERROR;
    while (p != NULL && j<i - 1)
    {
        p = p->next;
        j++;
    }
    if (p == NULL)return ERROR;
    q = p->next;    //指针q暂存被删结点(第i个结点)的地址,故指针q指向了被删结点
    p->next = q->next;    //指针p(即第i-1个结点的指针)指向被删结点的下一结点(第i+1个结点)
    e = q->data;
    free(q);
    return OK;
}

Status GetElem(LinkList L, int i, ElemType &e)    //取值
{
    int j = 1;
    LinkList p = L->next;
    if (i < 1)return ERROR;
    while (p != NULL && j<i)
    {
        p = p->next;
        j++;
    }
    if (p == NULL)return ERROR;
    e = p->data;
    return OK;
}

int LocateElem(LinkList L, ElemType e)    //定位
{
    int j = 1;
    LinkList p = L->next;
    while (p != NULL)
    {
        if (p->data == e)return j;
        p = p->next;
        j++;
    }
    return j;
}

Status PriorElem(LinkList L, ElemType e, ElemType &pr_e)    //直接前驱
{
    LinkList p = L->next;
    if (p->data==e)return ERROR;    //首结点没有直接前驱
    while (p != NULL)
    {
        p = p->next;
        if (p->next->data == e)break;
    }
    if (p == NULL)return ERROR;    //指针p一直移到尾结点仍找不到e,返回错误
    pr_e = p->data;
    return OK;
}

int GetLength(LinkList L)    //求长度
{
    int i = 0;
    LinkList p = L;
    while (p->next != NULL)
    {
        p = p->next;
        i++;
    }
    return i;
}

void PrnList(LinkList L)    //遍历
{
    LinkList p = L->next;
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

Status NiList(LinkList &L)    //逆置
{
    LinkList p = L->next, q;    //指针p指向了首结点
    L->next = NULL;    //将头结点指针置空
    while (p != NULL)
    {
        q = p;    //指针q从指向第一个结点开始后移
        p = p->next;    //指针p从指向第二个结点开始后移
        q->next = L->next;    //指针q所指向结点的指针q->next指向其上一个结点
        L->next = q;    //头结点的指针后移
    }
    return OK;
}

Status Destroy(LinkList &L)    //销毁,从首结点开始
{
    LinkList p = L->next, q;
    if (p == NULL)return ERROR;
    while (p != NULL)
    {
        q = p->next;
        free(p);
        p = q;
    }
    free(L);
    return OK;
}

int main()
{
    int i;
    ElemType e, e1;

    LinkList L;
    ElemType element[] = { 15, 3, 59, 27, 8, 11, 32 };
    if (InitList(L)) printf("OK\n");
    CreateList(L,element,7);
    PrnList(L);

    int k;
    printf("\n1.插入\n2:删除\n3:取值\n4:定位\n5:直接前驱\n");
    printf("6.求长度\n7:遍历\n8:逆置\n9:销毁\n\n0.退出\n");
    scanf("%d", &k);
    while (k != 0)
    {
        switch (k)
        {
        case 1:
            printf("在第几个位置插入何数:");
            scanf("%d%d", &i, &e);
            if (ListInsert(L, i, e)) printf("OK\n");
            break;
        case 2:
            printf("删除第几个数:");
            scanf("%d", &i);
            if (ListDelete(L, i, e))printf("删除数为:%d\n", e);
            break;
        case 3:
            printf("获取第几个数:");
            scanf("%d", &i);
            if (GetElem(L, i, e)) printf("数为:%d\n", e);
            break;
        case 4:
            printf("定位何数:");
            scanf("%d", &e);
            if (LocateElem(L, e)) printf("位序为:%d\n", LocateElem(L, e));
            break;
        case 5:
            printf("寻找何数直接前驱:");
            scanf("%d", &e);
            if (PriorElem(L, e, e1)) printf("前驱为:%d\n", e1);
            break;
        case 6:
            printf("表长为:");
            printf("%d\n", GetLength(L));
            break;
        case 7:
            printf("遍历:\n");
            PrnList(L);
            break;
        case 8:
            NiList(L);
            PrnList(L);
            printf("逆置成功\n");
            break;
        case 9:
            if (Destroy(L))printf("销毁成功\n");
            break;
        default:
            printf("ERROR\n");
        }
        scanf("%d", &k);
    }
    return 0;
}
View Code

 

posted @ 2019-12-11 10:17  举个栗子,举个锤子  阅读(979)  评论(0编辑  收藏  举报