单链表的实现和部分操作实验报告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 
#include 
#include 
#include 
#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)实验结果

单链表的实现和部分操作实验报告2(含完整代码)_第1张图片

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

PS:在这里面,就地逆序应该算一个小小的重头戏(滑稽)
这个实验里是定住首元结点,每次都把连在首元结点后的结点摘下来插到头指针之后
画图是这样的, 借用老师课件
单链表的实现和部分操作实验报告2(含完整代码)_第2张图片
也许还可以两端结点交换位置,直到中部(感觉没毛病,不过老师说这样不对)

另一种方法是 用三个指针, 让后一个的 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");
单链表的实现和部分操作实验报告2(含完整代码)_第3张图片

刚开始接触上手都难,如果程序一直运行不出来,注意创建链表那块儿, 再好好跟课本上的标准代码比对, 康康你有没有这样
单链表的实现和部分操作实验报告2(含完整代码)_第4张图片
等号是从右向左赋值的
我们并不想 让 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 的过程就是横着的那个箭头,意会一下?

单链表的实现和部分操作实验报告2(含完整代码)_第5张图片

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

如有不对,敬请指正呀

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

中间加上图片地址,尾部加上配对括号,很好,可以缩放图片了

你可能感兴趣的:(专业课)