线性表的链式存储-单链表,从认识到实践

单链表和顺序表都是线性表,其外在操作完全一致。唯一的差异就在存储结构上,就是这点差异导致了迥然不同的代码实现。话不多说,赶紧上车吧!
运行效果图:
1.单链表初始化过程
在这里插入图片描述

2.遍历单链表
在这里插入图片描述

3.为单链表追加元素
在这里插入图片描述

4.为单链表删除元素
在这里插入图片描述

5.为单链表插入元素
在这里插入图片描述

6.为单链表定位元素
在这里插入图片描述



。因单链表与顺序表的外在操作完全相同,故省去部分运行效果图


7.清空单链表
在这里插入图片描述
至此,运行效果图展示完毕!


附代码

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

#define OK 1
#define ERROR -1
#define SPAN 35;//菜单的水平跨度
#define VerticalGap 1//菜单的垂直间距,1就是一个换行,2就是两个换行
typedef struct node {
    int data;//数据域
    struct node *next;//指针域
} *NodePointer, Node;

NodePointer initialize();//初始化链表
void manifest(NodePointer originNodePointer);//遍历链表
int sort(NodePointer originNodePointer);//给链表排序
int inverse(NodePointer originNodePointer);//逆转链表中的所有结点的有效数据
void append(NodePointer originNodePointer, int value);//为链表追加结点,也就是在链表末尾添加一个结点
int insert(NodePointer originNodePointer, int position, int value);//在链表指定的位置上插入新结点
int delete(NodePointer originNodePointer, int position);//删除链表中某一结点的值
int modify(NodePointer originNodePointer, int position, int value);//修改表中的某一结点值
int getNode(NodePointer originNodePointer, int position, int *value);//通过结点下标获取结点值,如果成功获取返回1,否则返回-1
int locateNode(NodePointer originNodePointer, int value);//通过结点的值获取结点下标。若结点不存在或链表为空,则返回-1;若结点存在,则返回下标。
void clear(NodePointer originNodePointer);//清空链表
int isEmpty(NodePointer originNodePointer);//判断链表是否为空
void prompt(char *prompt);//运用了字符串和指针的知识,对printf的简单封装
void inputData(int *data, char *dataExplanation);//运用了字符串和指针的知识,对scanf和printf的简单封装
void menu(char **menu, int length);//动态地输出菜单
void duplicate(int size, char token);//给出一个整数size和一个字符型符号token,输出size个token,不换行
int main() {
    char *operatingMenu[] = {"LinkedList",
                             "1.reinitialize list", "2.present list", "3.append element",
                             "4.delete element", "5.insert element", "6.modify element",
                             "7.get element", "8.locate element", "9.sort", "10.inverse",
                             "11.clear list", "12.exit"};
    int length = sizeof(operatingMenu) / sizeof(char *);
    int indicator, position, value, status;
    NodePointer originNodePointer = initialize();
    while (1) {
        system("cls");
        menu(operatingMenu, length);
        if (originNodePointer == NULL || isEmpty(originNodePointer)) {
            prompt("The List Is Empty.Data are required!");
        } else {
            printf("CURRENT TOTAL:\t%d\n", originNodePointer->data);
            manifest(originNodePointer);
        }
        inputData(&indicator, "type in number:\t");
        switch (indicator) {
            case 1:
                if (isEmpty(originNodePointer)) {
                    free(originNodePointer);//若链表有效数据节点已经释放,则释放起源结点即可
                } else//否则,先释放链表有效数据节点,再释放起源结点
                {
                    clear(originNodePointer);
                    free(originNodePointer);//起源结点单独释放
                }
                originNodePointer = initialize();//给起源结点指针重新赋值
                system("pause");
                break;
            case 2:
                manifest(originNodePointer);
                system("pause");
                break;
            case 3:
                inputData(&value, "VALUE:");
                append(originNodePointer, value);
                manifest(originNodePointer);
                system("pause");
                break;
            case 4:
                inputData(&position, "POSITION:");
                status = delete(originNodePointer, position);
                (status == OK) ? manifest(originNodePointer) : prompt("check out and try again!");
                system("pause");
                break;
            case 5:
                inputData(&position, "POSITION:");
                inputData(&value, "VALUE:");
                status = insert(originNodePointer, position, value);
                (status == OK) ? manifest(originNodePointer) : prompt("check out and try again!");
                system("pause");
                break;
            case 6:
                inputData(&position, "POSITION:");
                inputData(&value, "VALUE:");
                status = modify(originNodePointer, position, value);
                (status == OK) ? manifest(originNodePointer) : prompt("check out and try again!");
                system("pause");
                break;
            case 7:
                inputData(&position, "POSITION:");
                status = getNode(originNodePointer, position, &value);
                (status == OK) ? printf("VALUE: %d\n", value) : prompt("check out and try again!");
                system("pause");
                break;
            case 8:
                inputData(&value, "VALUE:");
                position = locateNode(originNodePointer, value);
                (position == ERROR) ? prompt("check out and try again!") : printf("POSITION:%d\n", position);
                system("pause");
                break;
            case 9:
                status = sort(originNodePointer);
                (status == OK) ? manifest(originNodePointer) : prompt("check out and try again!");
                system("pause");
                break;
            case 10:
                status = inverse(originNodePointer);
                (status == OK) ? manifest(originNodePointer) : prompt("check out and try again!");
                system("pause");
                break;
            case 11:
                clear(originNodePointer);
                system("pause");
                break;
            case 12:
                if (isEmpty(originNodePointer))//若有效结点均已释放完毕
                {
                    free(originNodePointer);//释放起源结点
                } else//否则,先释放链表所有有效节点,再释放起源结点
                {
                    clear(originNodePointer);
                    free(originNodePointer);
                }
                exit(-1);
        }
    }
}

NodePointer initialize() {
    int length;
    inputData(&length, "The length of List:");
    if (length <= 0)
        exit(-1);
    NodePointer originNodePointer = (NodePointer) malloc(sizeof(Node));
    if (originNodePointer == NULL) {
        prompt("Failed To Allocate Memory!");
        exit(-1);
    }
    originNodePointer->data = 0;//起源结点的数据域存放有效结点的个数
    NodePointer newborn = originNodePointer;
    NodePointer temp;
    for (int i = 0; i < length; ++i) {
        temp = (NodePointer) malloc(sizeof(Node));
        printf("element %d:", i + 1);
        scanf("%d", &(temp->data));
        temp->next = NULL;
        newborn->next = temp;
        newborn = temp;
        originNodePointer->data++;//链表中有效结点的个数加1
    }
    return originNodePointer;
}

void manifest(NodePointer originNodePointer) {
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return;
    }
    NodePointer newborn = originNodePointer->next;
    printf("{");
    for (; newborn != NULL; newborn = newborn->next) {
        if (newborn->next != NULL)
            printf("%d\t", newborn->data);
        else
            printf("%d", newborn->data);
    }
    printf("}\n");
}

void append(NodePointer originNodePointer, int value) {
    NodePointer newborn = originNodePointer;
    NodePointer renascence = (NodePointer) malloc(sizeof(Node));
    if (renascence == NULL) {
        prompt("Failed To Allocate Memory!");
        exit(-1);
    }
    renascence->data = value;
    renascence->next = NULL;
    while (newborn->next != NULL) {
        newborn = newborn->next;
    }
    newborn->next = renascence;
    originNodePointer->data++;//起源结点存放链表有效结点的个数,在插入结点后加1
}

int insert(NodePointer originNodePointer, int position, int value) {
    //要想在链表中插入结点Amanda,先要定位到该结点Amanda上一个结点Natasha的位置
    //并且判断结点Natasha有没有后继结点,
    // 若没有,则表明Natasha就是链表表尾,插入的位置无效;
    //若有,则表明插入的位置合法,可以插入该结点
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return ERROR;
    }
    NodePointer newborn = originNodePointer;
    int i;
    for (i = 1; i < position && newborn->next != NULL; ++i)//我们从逻辑上将链表当作数组从前往后遍历
    {
        newborn = newborn->next;
    }
    if (i > position || newborn->next == NULL)//若输入的position小于0,则i>position,那么就判定position非法。再一个判断是否已经到达链表表尾
    {
        prompt("INVALID POSITION");
        return ERROR;
    }
    NodePointer renascence = (NodePointer) malloc(sizeof(Node));
    renascence->next = newborn->next;
    renascence->data = value;
    newborn->next = renascence;
    originNodePointer->data++;//结点数量加1
    prompt("The element is inserted completely!");
    return OK;
}

int delete(NodePointer originNodePointer, int position) {
    //删除结点与插入结点相同,同样要定位到要删除结点Amanda的上一个结点Natasha的位置,后面不再赘述
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return ERROR;
    }
    NodePointer newborn = originNodePointer;
    int i;
    for (i = 1; i < position && newborn->next != NULL; ++i) {
        newborn = newborn->next;
    }
    if (i > position || newborn->next == NULL) {
        prompt("INVALID POSITION");
        return ERROR;
    }
    NodePointer destroyedNode = newborn->next;
    newborn->next = destroyedNode->next;
    free(destroyedNode);
    originNodePointer->data--;
    prompt("The element is deleted successfully!");
    return OK;
}

int modify(NodePointer originNodePointer, int position, int value) {
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return ERROR;
    }
    if (position <= 0 || position > originNodePointer->data) {
        prompt("INVALID POSITION");
        return ERROR;
    }
    NodePointer newborn = originNodePointer;
    for (int i = 1; i <= position; ++i)
        newborn = newborn->next;
    newborn->data = value;
    prompt("The modification is completed!");
    return OK;
}

int getNode(NodePointer originNodePointer, int position, int *value) {
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return ERROR;
    }
    if (position <= 0 || position > originNodePointer->data) {
        prompt("INVALID POSITION");
        return ERROR;
    }
    NodePointer newborn = originNodePointer;
    for (int i = 1; i <= position; ++i) {
        newborn = newborn->next;
    }
    *value = newborn->data;
    return OK;
}

int locateNode(NodePointer originNodePointer, int value) {
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return ERROR;
    }
    NodePointer newborn = originNodePointer;
    int i = 1;
    int position;
    for (; i <= originNodePointer->data; ++i) {
        newborn = newborn->next;
        if (newborn->data == value) {
            position = i;
            break;
        }
    }
    if (i > originNodePointer->data) {
        prompt("The element you are looking for doesn't exist!");
        return ERROR;
    } else
        return position;
}

void clear(NodePointer originNodePointer)//清空链表时,保留起源起点
{
    if (originNodePointer->next == NULL) {
        prompt("There is no need to clear!");
        return;
    }
    NodePointer newborn = originNodePointer;
    NodePointer temporaryNode;
    int temp;
    for (int i = 1; i <= originNodePointer->data; ++i) {
        temporaryNode = newborn->next;
        temp = temporaryNode->data;
        newborn->next = temporaryNode->next;
        free(temporaryNode);
        printf("The element {\t%d\t} is released completely!\n", temp);
    }
    originNodePointer->data = 0;//起源结点的数据域存放链表有效结点的个数,在链表清空后归零
}

int sort(NodePointer originNodePointer)//这里用一个简单的选择排序
{
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return ERROR;
    }
    NodePointer competitor = originNodePointer->next;
    NodePointer opponent = NULL;
    NodePointer exchange = NULL;
    int temp;
    for (; competitor->next != NULL; competitor = competitor->next) {
        //最外层循环competitor只运算前n-1个元素,第n个元素已经是链表表尾,不参后续运算,循环结束
        exchange = competitor;
        for (opponent = competitor->next; opponent != NULL; opponent = opponent->next)
            //内层循环opponent运算到最后一个元素,最后一个元素指针域的指针为空,退出循环
            if (exchange->data > opponent->data)
                exchange = opponent;
        if (exchange != competitor) {
            temp = exchange->data;
            exchange->data = competitor->data;
            competitor->data = temp;
        }
    }
    prompt("Sorting is completed!");
    return OK;
}

int inverse(NodePointer originNodePointer) {
    if (isEmpty(originNodePointer)) {
        prompt("The List Is Empty");
        return ERROR;
    }
    NodePointer begin = originNodePointer->next;
    NodePointer end = originNodePointer->next;
    int counter = originNodePointer->data / 2;
    int temp;
    int j = 0;
    for (int i = 0; i < counter; i++, begin = begin->next) //从逻辑将链表有效节点当成数组来操作
    {
        while (j < originNodePointer->data - 1 - i)//定位到对应的交换节点位置
        {
            ++j;
            end = end->next;
        }
        //第一个有效结点和倒数第一个有效结点交互数据域,第二个有效结点和倒数第二个结点交换数据域,依此类推
        temp = end->data;
        end->data = begin->data;
        begin->data = temp;
        j = 0;
        end = originNodePointer->next;
    }
    prompt("Inverse is completed!");
    return OK;
}

int isEmpty(NodePointer originNodePointer) {
    if (originNodePointer->next == NULL)
        return 1;
    else
        return 0;
}

void inputData(int *data, char *dataExplanation) {
    printf("%s", dataExplanation);
    scanf("%d", data);
}

void prompt(char *prompt) {
    printf("%s\n", prompt);
}

void menu(char **origin, int length) {
    int span = SPAN;
    int gapLength;
    duplicate(span, '*');
    duplicate(1, '\n');
    for (int i = 0; i < length; ++i) {
        duplicate(1, '*');
        gapLength = span - (strlen(*(origin + i))) - 2;
        duplicate(gapLength / 2, ' ');
        printf("%s", origin[i]);
        if (gapLength % 2 == 0) {
            duplicate(gapLength / 2, ' ');
        } else {
            duplicate(gapLength / 2 + 1, ' ');
        }
        duplicate(1, '*');
        duplicate(VerticalGap, '\n');
    }
    duplicate(span, '*');
    duplicate(1, '\n');
}

void duplicate(int size, char token) {
    for (int i = 0; i < size; ++i) {
        printf("%c", token);
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值