单链表的实现和部分操作实验报告2(含完整代码)

仅供参考,记得看看自己班的课代表有没有发模板哦2333

实 验 报 告
课 程: 数据结构
班 级:
实验序号:
姓 名:
学 号:
实验日期:
题 目: 单链表基本操作的实现

一、实验目的和要求
①熟悉C语言的上机环境,进一步掌握C语言的结构特点。
②熟练掌握单链表的结构特点和基本操作。
③学会使用单链表解决实际问题。

二、实验环境
Windows2000 ,VB
三、实验内容及实施
(1)实验内容:
①创建一个带头结点的单链表(头指针为head),且遍历此链表(输出链表中各结点值)
定义一个函数 CreateList (LinkList &L, int n) 和 输出函数 print(LinkList &L)
②查找单链表中的第i个结点,并输出结点元素的值
定义一个函数 GetElem(LinkList L, int i, ElemType &target)
③在单链表中的第i个结点前插入一个结点值为e的正整数(从外部输入)
定义一个函数 ListInsert(LinkList &L, int i, ElemType e)
④删除单链表中的第j个结点
定义一个函数 ListDelete(LinkList &L, int j)
⑤将单链表中的各结点就地逆序(不允许另建一个链表)
定义一个函ListReverse(LinkList &L)
(2)源程序

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define LIST_INIT_SIZE 5
#define LISTINCREMENT 1
using namespace std;
typedef  int  Status;
typedef  int  ElemType; //表内元素类型为 int, 可更改

typedef struct LNode
{
    ElemType Data;  
    struct LNode *next;
}LNode, *LinkList;

int n, i, j;     //全局变量
ElemType e;

Status InitList (LinkList &L)
{
    L = new LNode;
    L -> next = NULL;
    return OK;
}

void print(LinkList &L) //遍历此链表(输出链表中各结点的值)
{
    printf("The new linear table is as follow:\n");
    LinkList p = L;
    while(p -> next)
    {
        p = p -> next;
        cout << p -> Data << ' ';
    }
    printf("\n");
}

void CreateList(LinkList &L, int n) //创建一个带头结点的单链表, 尾插
{
    printf("Please enter the number of elements:\n");
    cin >> n;
    printf("Please enter the elements:\n");
    L = new LNode;
    L -> next = NULL;
    LinkList r = L;
    for(int i = 0; i < n; ++i)
    {
        LinkList p = new LNode;
        cin >> p -> Data;
        r -> next = p;
        r = p;
    }
    r -> next = NULL;
    print(L);
}

Status GetElem(LinkList L, int i, ElemType &target) //查找单链表中的第i个结点,并输出结点元素的值, 用一个 target 是可以把这个值取出来,也许还有其他用处
{
    printf("Please enter the position to find:\n");
    cin >> i;
    LinkList p = L -> next;
    int j = 1;
    while(p && j < i)
    {
        p = p -> next;
        ++j;
    }
    if(!p || j > i)
        return ERROR;
    target = p -> Data;
    cout << target << endl;
    return OK;
}

Status ListInsert(LinkList &L, int i, ElemType e) //在单链表中的第i个结点前插入一个结点值为e的正整数(从外部输入)
{
    LinkList p = L;
    int j = 0;
    printf("Please enter the insertion position and value:\n");
    cin >> i >> e;
    while(p && j < i-1)
    {
        p = p -> next;
        ++j;
    }
    if(!p || j > i-1)
        return ERROR;
    LinkList q = new LNode;
    q -> Data = e;
    q -> next = p -> next;
    p -> next = q;
    print(L);
    return OK;
}

Status ListDelete(LinkList &L, int j) //删除单链表中的第j个结点
{
    printf("Enter the position of the element to delete:\n");
    cin >> j;
    LinkList p = L;
    int i = 0;
    while((p -> next) && (i < j-1)) //删除第个 j 结点, 让指向第 j-1 个结点, 方便删掉其下一个即第 j 个结点
    {
        p = p -> next;
        ++i;
    }
    if(!(p -> next) || (i > j-1))
        return ERROR;
    LinkList q = p -> next;
    p -> next = q -> next;
    delete q;
    print(L);
    return OK;
}

Status ListReverse(LinkList &L) //将单链表中的各结点就地逆序(不允许另建一个链表)
{
    LinkList p = L -> next; //一直用指针 p 指向最初的首元结点,逆序后成为尾结点
    if(p)
    {
        LinkList q = p -> next; //指向 p 的下一结点
        if(q)
        while(q)
        {
            p -> next = q -> next; //连上 q 的下一结点,把 q 取出来
            q -> next = L -> next; //把 q 插到头结点之后
            L -> next = q;
            q = p -> next; //指向 p 的下一结点
        }
    }
    print(L);
    return OK;
}

int main()
{
    int num;
    ElemType target;
    LinkList head;
    printf("What do you want to do?\n");
    printf("0.退出程序\n");
    printf("1.创建一个带头结点的单链表(头指针为head),且遍历此链表(输出链表中各结点的值)\n");
    printf("2.查找单链表中的第i个结点,并输出结点元素的值\n");
    printf("3.在单链表中的第i个结点前插入一个结点值为e的正整数(从外部输入)\n");
    printf("4.删除单链表中的第j个结点\n");
    printf("5.将单链表中的各结点就地逆序(不允许另建一个链表)\n");
    printf("Please enter the serial number of the operation you want to perform:\n");
    while(cin >> num)
    {
        switch(num)
        {
            case 0: exit(0);
            case 1: InitList(head);
                    CreateList(head, n); break;
            case 2: GetElem(head, i, target); break;
            case 3: ListInsert(head, i, e); break;
            case 4: ListDelete(head, j); break;
            case 5: ListReverse(head); break;
            default: printf("The serial number is illegal.Please enter again:\n");
        }
        printf("\nPlease enter the serial number of the operation you want to perform:\n");
    }
    return 0;
}

(3)实验结果

四、实验感想
通过这次实验,同时对比顺序表的学习,我初步掌握了单链表的结构特点和基本操作,巩固了C语言相关的程序设计方法与技术,并且意识到,熟练掌握课本知识是实验的基础,不把课本上的相关知识学深学透, 实验便无从着手, 另外,在做实验的过程锻炼思考问题并动手解决的能力很重要。

PS:在这里面,就地逆序应该算一个小小的重头戏(滑稽)
这个实验里是定住首元结点,每次都把连在首元结点后的结点摘下来插到头指针之后
画图是这样的, 借用老师课件
在这里插入图片描述
也许还可以两端结点交换位置,直到中部(感觉没毛病,不过老师说这样不对)

另一种方法是 用三个指针, 让后一个的 next 指针指向前面,因为从尾部往前指较难实现,所以这里从 head 指针的后面,通过三个指针慢慢向尾部推进, 实现所有 next 指针反向

班里大佬的代码和配图

void reverse(Plist list)//逆置
{
	Plist pre, cur, rear;
	pre = list;
	if (pre->next == NULL) {
		printf("该链表只有一个元素,无需置换");
		exit(0);
	}
	pre = list->next;
	cur = pre->next;
	pre->next = NULL;
	while(cur)
	{
		rear = cur->next;//防止cur最后为空时rear找不到cur所指的next
		cur->next = pre;
		pre = cur;
		cur = rear;
	}
	list->next = pre;
	printf("逆置完成\n");

刚开始接触上手都难,如果程序一直运行不出来,注意创建链表那块儿, 再好好跟课本上的标准代码比对, 康康你有没有这样
在这里插入图片描述
等号是从右向左赋值的
我们并不想 让 p 指向 head -> next (此时 head -> next 是未定的啊喂 ), 而是想让p 连在 head 后面, 就是让 head -> next = p 啊

如果还有一丝丝疑惑 ,接着向下看(打出来的字绝对不能白费)

head 申请了空间, 是一个结点, 而 head->next 未赋值, 所以指向是随机的(这很危险),我们让 head->next = p 的前提是 p 是一个结点, 是已经通过 malloc 或 new 申请了空间的结点,让上一个结点的 next 指针指向下一个结点, 这样就把两个结点串了起来
而在head->next 未赋值的情况下,p=head->next 是没有任何意义的

我那个程序创建的过程是下面这个丑图,r -> next = p 的过程就是横着的那个箭头,意会一下?

解释一下就是: 在单链表尾部连上一个结点之后,让 r 指向链表的尾部, 申请新结点 p,输入数据值,通过 r -> next = p 把 p 连在 r 的后面,即把 p 接在链表尾部, 然后让 r 再次指向链表尾部(即 r = p ),如此这般,重复操作
这就是尾插创建单链表

如有不对,敬请指正呀

配图同时 get 到新技能
图片链接里面加上宽度百分比

<img src=“https://” width=“20%”
中间加上图片地址,尾部加上配对括号,很好,可以缩放图片了

  • 17
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
单链表实验报告 1. 实验目的与要求 1、实现单链表的建立; 2、掌握单链表的插入、删除和查找运算; 3、熟练进行C语言源程序的编辑调试。 2. 实验内容 (1)建立带表头结点的单链表; 首先输入结束标志,然后建立循环逐个输入数据,直到输入结束标志。 数据输入的函数为: LNode *createtail() { LNode *s,*r; int x,tag; printf("input the sign of ending:"); /*输入结束标志*/ scanf("%d",&tag); h=(LNode * )malloc(sizeof(LNode)); /*建立表头结点*/ h->data=tag; r=h; printf("input the data:"); scanf("%d",&x); while(x!=tag) /*建立循环逐个输入数据*/ { s=(LNode * )malloc(sizeof(LNode)); s->data=x; r->link=s; r=s; scanf("%d",&x); } r->link=NULL; return h; } (2)输出单链表中所有结点的数据域值; 首先获得表头结点地址,然后建立循环逐个输出数据,直到地址为空。 数据输出的函数为: void output(LNode *h) { LNode *r; int i; r=h; for(i=1;r->link!=NULL;i++) { printf("%d.%d\n",i,r->link->data); r=r->link; } } (3)输入x,y在第一个数据域值为x的结点之后插入结点y,若无结点x,则在表尾插 入结点y; 建立两个结构体指针,一个指向当前结点,另一个指向当前结点的上一结点,建立循 环扫描链表。当当前结点指针域不为空且数据域等于x的时候,申请结点并给此结点 数据域赋值为y,然后插入当前结点后面,退出函数;当当前结点指针域为空的时候 ,申请结点并给此结点数据域赋值为y,插入当前结点后面,退出函数。 数据插入函数为: void insert(LNode *h) { LNode *r,*s; int x,y; printf("Input the data that you want to insert:\n"); printf("x="); scanf("%d",&x); /*输入x值*/ printf("y="); scanf("%d",&y); /*输入y值*/ r=h; r=r->link; for(;;r=r->link) { if(r->data==x) /*当当前结点指针域不为空且数据域等于x的时候…*/ { s=(LNode *)malloc(sizeof(LNode)); s->data=y; s->link=r->link; r->link=s; break; } if(r->link==NULL) /*当当前结点指针域为空的时候*/ { s=(LNode *)malloc(sizeof(LNode)); s->data=y; s->link=NULL; r->link=s; break; } } } (4)输入k,删除单链表中所有的结点k,并输出被删除结点的个数。 建立三个结构体指针,一个指向当前结点,另一个指向当前结点的上一结点,最后一 个备用;建立整形变量l=0;建立循环扫描链表。当当前结点指针域为空的时候,如 果当前结点数据域等于k,删除此结点,l++,跳出循环,结束操作;如果当前结点数 据域不等于k,跳出循环,结束操作。当当前结点指针域不为空的时候,如果当前结 点数据域等于k,删除此结点,l++,继续循环操作;如果当前结点数据域不等于k, 指针向后继续扫描。循环结束后函数返回变量l的值,l便是删除的结点的个数。 数据删除函数为: int del(LNode *h) { LNode *r,*s,*t; int k,l=0; printf("Input the data that you want to delete:"); scanf("%d",&k); r=h; s=r; r=r->link; for(;;) { if(r->link==NULL) /*当当前结点指针域为空的时候*/ { if(r->data==k) /*如果当前结点数据域不等于k…*/ { l++; s->link=NULL; free(r); break; } else break; /*如果当前结点数据域等于k…*/ } else /*当当前结点指针域不为空的时候*/ { if(r->data==k) /*如果当前结点数据域不等于k…*/ { l++; t=r; s->link=t->link; r=t->lin
以下是C++实现单链表的插入和删除操作的示例代码: ```c++ #include<iostream> using namespace std; //定义链表结构体 struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; //链表插入操作 void insertNode(ListNode* &head, int val) { ListNode* newNode = new ListNode(val); if(head == NULL) { head = newNode; } else { ListNode* cur = head; while(cur->next != NULL) { cur = cur->next; } cur->next = newNode; } } //链表删除操作 void deleteNode(ListNode* &head, int val) { if(head == NULL) return; if(head->val == val) { head = head->next; } else { ListNode* cur = head; while(cur->next != NULL && cur->next->val != val) { cur = cur->next; } if(cur->next != NULL) { cur->next = cur->next->next; } } } //链表遍历 void printList(ListNode* head) { ListNode* cur = head; while(cur != NULL) { cout << cur->val << " "; cur = cur->next; } } int main() { ListNode* head = NULL; insertNode(head, 1); insertNode(head, 2); insertNode(head, 3); insertNode(head, 4); cout << "插入操作后的链表为:"; printList(head); deleteNode(head, 2); deleteNode(head, 4); cout << "\n删除操作后的链表为:"; printList(head); return 0; } ``` 在上述代码中,我们首先定义了一个链表结构体 `ListNode`,其中包节点的值 `val` 和指向下一个节点的指针 `next`。然后,我们实现了链表的插入操作 `insertNode` 和删除操作 `deleteNode`。最后,我们通过 `printList` 函数遍历链表,输出链表中的每个节点的值。 在 `main` 函数中,我们先创建一个空链表 `head`,然后依次插入节点,最后输出插入节点后的链表。然后,我们删除链表中的节点2和节点4,并输出删除节点后的链表。 运行上述代码,输出结果如下: ``` 插入操作后的链表为:1 2 3 4 删除操作后的链表为:1 3 ``` 可以看到,我们成功地实现单链表的插入和删除操作,并正确输出了链表中节点的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值