【上机实验】02:链表原地翻转

链表原地翻转


程序内部:在程序中能够看到的部分,链表中指第一个节点的地址(head指针记录整个链表的地址)

内存内部:在程序中不能看到的部分,链表中指的每一个节点(体现在物理内存中)

在这里插入图片描述

1.链表操作
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

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

typedef struct LinkList{
    Node head;//head为虚拟头结点
    int length;
}LinkList;

//1.初始化结点
Node *initNode(int val){
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = val;
    node->next = NULL;
    return node;
}

//2.初始化链表
LinkList *initList(){
    LinkList *llst = (LinkList *)malloc(sizeof(LinkList));
    llst->head.next = NULL;
    llst->length = 0;
    return llst;
}

//3.结点的销毁
void DestroyNode(Node *node){
    if(node == NULL) return;
    free(node);
    return;
}

//4.链表的销毁
void DestroyList(LinkList *llst){
    if(llst == NULL) return;
    Node *p = llst->head.next;
    Node *temp;
    while (p != NULL) {
        temp = p->next;
        DestroyNode(p);
        p = temp;
    }
    free(llst);
    return;
}

//5.链表插入
int ListInsert(LinkList *llst, int ind, int val){
    if(llst == NULL) return 0;
    if(ind < 0 || ind > llst->length) return 0;
    Node *p = &(llst->head);//指针p记录虚拟头结点地址
    //(1)初始化一个node结点存入val数据
    Node *node = initNode(val);
    //(2)找到插入位置的前一个位置
    while(ind--) p = p->next;
    //(3)重新建立索引关系,进行结点插入
    node->next = p->next;
    p->next = node;
    llst->length += 1;
    return 1;
}

//6.链表元素的删除操作
int ListDelete(LinkList *llst, int ind) {
    if(llst == NULL) return 0;
    if(ind < 0 || ind >= llst->length) return 0;
    //(1)初始化一个node结点存入val数据
    Node *p = &(llst->head);
    Node *temp;
    //(2)找到插入位置的前一个位置
    while(ind--) p = p->next;
    //(3)temp记录待删除结点位置,进行删除操作
    temp = p->next;
    p->next = p->next->next;
    DestroyNode(temp);
    llst->length -= 1;
    return 1;
}

//7.print链表
void print(LinkList *llst) {
    if(llst == NULL) return;
    printf("LinkList(%d) : ", llst->length);
    //遍历LinkList元素
    for(Node *p = llst->head.next; p != NULL; p = p->next) {
        printf("%d->", p->data);
    }
    printf("NULL\n");
    return;
}

int main(){
    srand(time(0));
    LinkList *llst = initList();
    #define MAX_OP 20
    for(int i = 0; i < MAX_OP; ++i){
        int val = rand() % 100;
        int ind = rand() % (llst->length + 3) - 1;//操作位置随机在范围[-1, sqlst-length + 1]中
        int op = rand() % 4;
        switch (op) {
            case 0:
            case 1:
            case 2: {
                printf("insert %d at %d to List = %d\n", val, ind, ListInsert(llst, ind, val));
            } break;
            case 3: {
                printf("erase a item at %d from List = %d\n", ind, ListDelete(llst, ind));
            } break;
        }
        print(llst);
    }
    #undef MAX_OP
    DestroyList(llst);
    return 0;
}

在这里插入图片描述

注意:对程序内部和内存内部的理解,决定了链表数据结构的定义方式

2.链表原地翻转

思路1

  1. 新创建一个链表
  2. 遍历已知的链表,将元素不断的插入到新创建的链表中(使用头插法)

思路2

原地翻转链表,不需要开辟新的空间O(1),注意内存泄漏问题

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

#define COLOR(a,b) "\033[" #b "m" a "\033[0m"
#define GREEN(a) COLOR(a, 34)

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

typedef struct LinkList{
    Node head;//head为虚拟头结点
    int length;
}LinkList;

//1.初始化结点
Node *initNode(int val){
    Node *node = (Node *)malloc(sizeof(Node));
    node->data = val;
    node->next = NULL;
    return node;
}

//2.初始化链表
LinkList *initList(){
    LinkList *llst = (LinkList *)malloc(sizeof(LinkList));
    llst->head.next = NULL;
    llst->length = 0;
    return llst;
}

//3.结点的销毁
void DestroyNode(Node *node){
    if(node == NULL) return;
    free(node);
    return;
}

//4.链表的销毁
void DestroyList(LinkList *llst){
    if(llst == NULL) return;
    Node *p = llst->head.next;
    Node *temp;
    while (p != NULL) {
        temp = p->next;
        DestroyNode(p);
        p = temp;
    }
    free(llst);
    return;
}

//5.链表插入
int ListInsert(LinkList *llst, int ind, int val){
    if(llst == NULL) return 0;
    if(ind < 0 || ind > llst->length) return 0;
    Node *p = &(llst->head);//指针p记录虚拟头结点地址
    //(1)初始化一个node结点存入val数据
    Node *node = initNode(val);
    //(2)找到插入位置的前一个位置
    while(ind--) p = p->next;
    //(3)重新建立索引关系,进行结点插入
    node->next = p->next;
    p->next = node;
    llst->length += 1;
    return 1;
}

//6.链表元素的删除操作
int ListDelete(LinkList *llst, int ind) {
    if(llst == NULL) return 0;
    if(ind < 0 || ind >= llst->length) return 0;
    //(1)初始化一个node结点存入val数据
    Node *p = &(llst->head);
    Node *temp;
    //(2)找到插入位置的前一个位置
    while(ind--) p = p->next;
    //(3)temp记录待删除结点位置,进行删除操作
    temp = p->next;
    p->next = p->next->next;
    DestroyNode(temp);
    llst->length -= 1;
    return 1;
}

//7.链表原地翻转
void ListReverse(LinkList *llst){
	if(llst == NULL) return;
    Node *p = llst->head.next;
    Node *temp;
    llst->head.next = NULL;
    while(p != NULL){
        temp = p->next;
        p->next = llst->head.next;
        llst->head.next = p;
        p = temp;
    }
    return;
}

//7.print链表
void print(LinkList *llst) {
    if(llst == NULL) return;
    printf("LinkList(%d) : ", llst->length);
    //遍历LinkList元素
    for(Node *p = llst->head.next; p != NULL; p = p->next) {
        printf("%d->", p->data);
    }
    printf("NULL\n");
    return;
}

int main(){
    srand(time(0));
    LinkList *llst = initList();
    #define MAX_OP 20
    for(int i = 0; i < MAX_OP; ++i){
        int val = rand() % 100;
        int ind = rand() % (llst->length + 3) - 1;//操作位置随机在范围[-1, sqlst-length + 1]中
        int op = rand() % 4;
        switch (op) {
            case 0: {
                printf(GREEN("reverse the list!\n"));
                ListReverse(llst);
            } break;
            case 1:
            case 2: {
                printf("insert %d at %d to List = %d\n", val, ind, ListInsert(llst, ind, val));
            } break;
            case 3: {
                printf("erase a item at %d from List = %d\n", ind, ListDelete(llst, ind));
            } break;
        }
        print(llst);
    }
    #undef MAX_OP
    DestroyList(llst);
    return 0;
}

在这里插入图片描述

ListReverse操作:

//7.链表原地翻转
void ListReverse(LinkList *llst){
    if(llst == null) return;
    Node *p = head->next;
    Node *temp;
    head->next = NULL;
    while(p != NULL){
        temp = p->next;
        p->next = head->next;
        head->next = p;
        p = temp;
    }
    return;
}

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值