一、实验目的:
1、线性表的链表实现:遍历、查找、插入、删除、翻转
2、栈的链式存储结构实现:入栈、出栈
3、队列的链式存储结构的实现:入队、出队
4、线性表、栈和队列的应用实现
二、实验类型: 验证性
三、实验学时:4学时(二周)
四、实验教学的重点和难点:
重点:线性表、堆栈和队列链式存储结构的C或C++语言的实现方法
难点:指针操作
五、实验内容:
1、单链表实验、实现单链表的基本功能
(1)实现链表结点的创建功能
(2)实现单链表的创建功能
(3)实现单链表的插入功能
(4)实现单链表的删除功能
(5)实验单链表某个数据的查找(成功或不成功,成功时位置)
#include
#include
#include
#include
struct Node
{
int data; //数据域
struct Node* next; //指针域
int length; //链表长度
};
//创建链表
struct Node* createList()
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->next = NULL;
return headNode;
}
//创建结点,有数据域
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
//打印链表
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
for (int i = 0; i < headNode->length; i++)
{
printf("%d ", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
//插入(头插法)
void insertNodeHead(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
headNode->length++;
}
//指定位置插入
void insertNodePos(struct Node* headNode, int data, int pos)
{
struct Node* newNode = createNode(data);
struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
pNode = headNode;
if (pos > (headNode->length + 1))
printf("插入位置不合理!\n");
else
{
for (int i = 0; i < pos - 1; i++)
pNode = pNode->next;
newNode->next = pNode->next;
pNode->next = newNode;
headNode->length++;
printf("插入成功!\n");
}
}
//删除结点
void deleteNode(struct Node* headNode, int posdata)
{
struct Node* posNode = headNode->next;
struct Node* posNodefront = headNode;
if (posNode == NULL)
printf("链表为空,无法删除!\n");
else
{
while (posNode->data != posdata)
{
posNodefront = posNode;
posNode = posNodefront->next;
if (posNode == NULL)
{
printf("没有找到相关信息,无法删除!\n");
return;
}
}
posNode = posNodefront->next; //临时保存被删结点的地址以备释放
posNodefront->next = posNode->next;
free(posNode);
headNode->length--;
printf("删除成功!\n");
}
}
//查找
void findNode(struct Node* headNode, int data)
{
struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
pNode = headNode->next;
int i = 0;
while (pNode->next)
{
i++;
if (pNode->data == data)
{
printf("查找成功!该数据位于链表的第 %d 位\n", i);
break;
}
pNode = pNode->next;
}
if (pNode->next == NULL)
printf("查找失败,该数据不在链表中!\n");
}
2、线性表的链表实现:
(1)用随机函数生成10个3位整数(100~999),把这些整数存于链表中;
(2)输出链表的内容;
(3)读入一个整数,查看该整数是否在表中,若在,输出其位置(首位置为1);
(4)读入一个整数,以及要插入的位置,把该整数插入到链表中,输出链表的内容(要求判断输入的位置是否合理);
(5)读入一个整数,若该整数在链表里,删除该整数,输出链表的内容;
(6)把链表的内容翻转,输出链表的内容。
#include
#include
#include
#include
struct Node
{
int data; //数据域
struct Node* next; //指针域
int length; //链表长度
};
//创建链表
struct Node* createList()
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->next = NULL;
return headNode;
}
//创建结点,有数据域
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
//打印链表
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
for (int i = 0; i < headNode->length; i++)
{
printf("%d ", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
//插入(头插法)
void insertNodeHead(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
headNode->length++;
}
//指定位置插入
void insertNodePos(struct Node* headNode, int data, int pos)
{
struct Node* newNode = createNode(data);
struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
pNode = headNode;
if (pos > (headNode->length + 1))
printf("插入位置不合理!\n");
else
{
for (int i = 0; i < pos - 1; i++)
pNode = pNode->next;
newNode->next = pNode->next;
pNode->next = newNode;
headNode->length++;
printf("插入成功!\n");
}
}
//删除结点
void deleteNode(struct Node* headNode, int posdata)
{
struct Node* posNode = headNode->next;
struct Node* posNodefront = headNode;
if (posNode == NULL)
printf("链表为空,无法删除!\n");
else
{
while (posNode->data != posdata)
{
posNodefront = posNode;
posNode = posNodefront->next;
if (posNode == NULL)
{
printf("没有找到相关信息,无法删除!\n");
return;
}
}
posNode = posNodefront->next; //临时保存被删结点的地址以备释放
posNodefront->next = posNode->next;
free(posNode);
headNode->length--;
printf("删除成功!\n");
}
}
//查找
void findNode(struct Node* headNode, int data)
{
struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
pNode = headNode->next;
int i = 0;
while (pNode->next)
{
i++;
if (pNode->data == data)
{
printf("查找成功!该数据位于链表的第 %d 位\n", i);
break;
}
pNode = pNode->next;
}
if (pNode->next == NULL)
printf("查找失败,该数据不在链表中!\n");
}
//翻转(一直往后迭代)
void reverseNode(struct Node* headNode)
{
struct Node* p1 = NULL; //前一个
struct Node* p2 = headNode->next; //后一个
while (p2)
{
struct Node* nextNode = p2->next;
p2->next = p1;
p1 = p2;
p2 = nextNode;
}
headNode->next = p1->next;
}
int main()
{
time_t t;
srand((unsigned)time(&t));
struct Node* headNode, * pNode;
headNode = (struct Node*)malloc(sizeof(struct Node)); //初始化头结点
pNode = (struct Node*)malloc(sizeof(struct Node)); //申请第一个结点
headNode->next = pNode; //连接俩结点
//随机函数生成10个3位整数(100~999)存于链表中并输出
printf("该链表为:\n");
for (int i = 0; i < 10; i++)
{
pNode->data = rand() % 900 + 100;
printf("%d ", pNode->data);
pNode->next = (struct Node*)malloc(sizeof(struct Node)); //申请下一个结点
pNode = pNode->next; //将两结点连起来
}
headNode->length = 10;
pNode->next = NULL; //尾结点next指向空
printf("\n");
int choice = 0;
do
{
printf("\n 1 - 查找, 2 - 插入, 3 - 删除, 4 - 翻转, 0 - 退出\n 请选择:");
scanf_s("%d", &choice);
printf("\n");
switch (choice)
{
case 1:
{
int num = 0;
printf("请输入要查找的数据:");
scanf_s("%d", &num);
findNode(headNode, num);
break;
}
case 2:
{
int num = 0, pos = 0;
printf("请输入要插入的数据:");
scanf_s("%d", &num);
printf("请输入要插入的位置:");
scanf_s("%d", &pos);
insertNodePos(headNode, num, pos);
printf("链表为:\n");
printList(headNode);
break;
}
case 3:
{
int num = 0;
printf("请输入要删除的数据:");
scanf_s("%d", &num);
deleteNode(headNode, num);
printf("链表为:\n");
printList(headNode);
break;
}
case 4:
{
reverseNode(headNode);
printf("链表翻转后为:\n");
printList(headNode);
break;
}
case 0:
printf("感谢使用!\n"); break;
}
} while (choice);
free(headNode);
free(pNode);
return 0;
}
3、栈的顺序存储结构实现
(1)用随机函数生成10个3位整数(100~999),把这些整数应用入栈操作存于堆栈中,在入栈接口处设置断点①,按“F5”启动调试,按“F10”逐句执行,直到数据全部入栈。程序暂停时观察栈顶数据和栈顶位置;
入栈完成top指针在栈顶元素的上方
(2)应用出栈操作输出堆栈的内容,在出栈接口处设置断点②,按“F5”启动调试,按“F10”逐句执行,直到所有数据完全出栈,程序暂停时观察栈顶数据和栈顶位置的变化;
出栈完成base指针等于top指针
#include
#include
#include
#include
#define maxsize 100
struct SqStack
{
int* base;
int* top;
int stacksize;
};
//初始化
void InitStack(struct SqStack* S)
{
S->base = (int*)malloc(sizeof(int) * maxsize);
if (!S->base)
exit(-2); //存储内存分配失败
S->top = S->base; //top初始为base,空栈
S->stacksize = maxsize; //stacksize置为栈的最大容量maxsize
}
//入栈
int Push(struct SqStack* S, int data) //插入元素data为新的栈顶元素
{
if (S->top - S->base == S->stacksize) //栈满
return 0;
*S->top = data;
++S->top; //将新元素压入栈顶,栈顶指针加1
return 1;
}
//出栈
int Pop(struct SqStack* S) //删除S的栈顶元素,用data返回其值
{
int data;
if (S->top == S->base)
return 0; //栈空
--S->top;
data = *S->top; //栈顶指针减1,将栈顶元素赋给data
printf("%d ", data);
return 1;
}
//取栈顶元素
int GetTop(struct SqStack* S) //返回S的栈顶元素,不修改栈顶指针
{
if (S->top != S->base)
return *(S->top - 1); //栈非空,返回栈顶元素的值,栈顶指针不变
}
void PrintStack(struct SqStack* S)
{
while(S->top != S->base)
printf("%d ", *S->base++);
printf("\n");
}
int main()
{
time_t t;
srand((unsigned)time(&t));
struct SqStack* S;
S = (struct SqStack*)malloc(sizeof(struct SqStack));
InitStack(S);
int data = 0;
printf("入栈顺序:\n");
for (int i = 0; i < 10; i++)
{
data = rand() % 900 + 100;
printf("%d ", data);
Push(S, data);
}
printf("\n");
printf("出栈顺序:\n");
while(S->top != S->base)
Pop(S);
printf("\n\n");
free(S);
system("pause");
return 0;
}
4、队列的链式存储结构的实现
(1)用随机函数生成10个3位整数(100~999),把这些整数应用入队操作存于队列中;
(2)应用遍历操作输出队列的内容;
(3)把队列的内容翻转,应用出队操作输出队列的内容。
#include
#include
#include
#include
//结点
struct QNode
{
int data;
struct QNode* next;
};
//队列
struct Queue
{
struct QNode* front; //队头指针
struct QNode* rear; //队尾指针
};
//初始化
void InitQueue(struct Queue* Q)
{
Q->front = Q->rear = (struct QNode*)malloc(sizeof(struct QNode)); //生成新结点作为头结点,队头和队尾指针指向此结点
Q->front->next = NULL; //头结点的指针域置空
}
//入队,插入元素为Q的新的队尾元素
void EnterQueue(struct Queue* Q, int data)
{
struct QNode* pNode = (struct QNode*)malloc(sizeof(struct QNode)); //为入队元素分配结点空间,用指针pNode指向
pNode->data = data; //将新结点数据域置为data
pNode->next = NULL; //将新结点插入到队尾
Q->rear->next = pNode; //修改队尾指针
Q->rear = pNode;
}
//出队,删除Q的队头元素,用data返回
void DeQueue(struct Queue* Q, int data)
{
struct QNode* p;
if (Q->front == Q->rear) //若队列为空,则结束
return;
p = Q->front->next; //p指向队头元素
data = p->data; //data保存队头元素的值
printf("%d ", data);
Q->front->next = p->next; //修改头结点的指针域
if (Q->rear == p) //最后一个元素被删, 队尾指针指向头结点
Q->rear = Q->front;
free(p); //释放原队头元素的空间
}
//取链队的队头元素
int GetHead(struct Queue* Q)
{
if (Q->front != Q->rear) //队列非空
return Q->front->next->data; //返回Q的队头元素,不修改队头指针
}
//遍历操作输出队列内容
void printQueue(struct Queue* Q)
{
struct QNode* pnode = Q->front; //Q相当于头结点
while (pnode->next)
{
pnode = pnode->next;
printf("%d ", pnode->data);
}
printf("\n");
}
//将队列内容翻转
void reverseQueue(struct Queue* Q)
{
struct QNode* p1 = Q->front->next; //front
struct QNode* p2 = p1->next; //front下一个
struct QNode* nextNode = p2->next;
Q->rear = p1;
while (nextNode)
{
p2->next = p1;
p1 = p2;
p2 = nextNode;
nextNode = p2->next;
} //循环结束后p2在原来rear的位置
p2->next = p1; //p1在原来rear的上一个
Q->front->next = p2; //Q相当于头结点,它的next就是链队的front,变为原来rear的位置
Q->rear->next = NULL;
}
int main()
{
time_t t;
srand((unsigned)time(&t));
struct Queue* Q;
Q = (struct Queue*)malloc(sizeof(struct Queue));
InitQueue(Q);
int data = 0;
printf("元素入队顺序为:\n");
for (int i = 0; i < 10; i++)
{
data = rand() % 900 + 100;
printf("%d ", data);
EnterQueue(Q, data);
}
printf("\n遍历操作输出队列内容:\n");
printQueue(Q);
int num = 0;
reverseQueue(Q);
printf("把队列的内容翻转,应用出队操作输出队列的内容:\n");
while (Q->front->next)
DeQueue(Q, data);
printf("\n");
free(Q);
return 0;
}
5、线性表、栈和队列的应用
(1)用随机函数生成10个3位整数(100~999),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。
#include
#include
#include
#include
struct Node
{
int data;
struct Node* next;
};
struct Node* createList()
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->next = NULL;
return headNode;
}
void insertHead(struct Node* headNode, int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->next = headNode->next;
newNode->data = data;
headNode->next = newNode;
}
void printList(struct Node* headNode)
{
struct Node* pNode = headNode->next;
while (pNode->next)
{
printf("%d ", pNode->data);
pNode = pNode->next;
}
printf("\n");
}
//排序
void sortList(struct Node* headNode)
{
struct Node* p1 = headNode->next;
struct Node* p2 = p1->next;
while (p1->next)
{
while (p2->next)
{
if (p1->data > p2->data)
{
int temp = p1->data;
p1->data = p2->data;
p2->data = temp;
}
p2 = p2->next;
}
p1 = p1->next;
p2 = p1->next;
}
}
int main()
{
time_t t;
srand((unsigned)time(&t));
struct Node* headNode, * pNode;
headNode = (struct Node*)malloc(sizeof(struct Node));
pNode = (struct Node*)malloc(sizeof(struct Node));
headNode->next = pNode;
printf("链表元素为:\n");
for (int i = 0; i < 10; i++)
{
pNode->data = rand() % 900 + 100;
printf("%d ", pNode->data);
pNode->next = (struct Node*)malloc(sizeof(struct Node));
pNode = pNode->next;
}
pNode->next = NULL;
int num = 0;
printf("\n请输入一个数:");
scanf_s("%d", &num);
insertHead(headNode, num);
printf("以该值为基准把单链表分割为两部分:\n");
sortList(headNode);
printList(headNode);
free(headNode);
free(pNode);
return 0;
}
(2)假设一个字符串中可以包含三种括号:( )[ ]{},且这三种括号可以按任意次序嵌套使用(如:“...[...{...}...[...]...]...(...)” 为合法嵌套,“...[...{... )...[...]...]...(...)”为不合法嵌套)。编写判别给定表达式中所含括号是否正确配对出现的算法,如果是合法嵌套则返回为true,如果是不符合法嵌套则返回为false。
#include
#include
#define maxsize 10
struct SqStack
{
int* base;
int* top;
int stacksize;
};
//初始化
void InitStack(struct SqStack* S)
{
S->base = (int*)malloc(sizeof(int) * maxsize);
if (!S->base)
exit(-2); //存储内存分配失败
S->top = S->base; //top初始为base,空栈
S->stacksize = maxsize; //stacksize置为栈的最大容量maxsize
}
//入栈
int Push(struct SqStack* S, char ch) //插入元素data为新的栈顶元素
{
if (S->top - S->base == S->stacksize) //栈满
return 0;
*S->top = ch;
++S->top; //将新元素压入栈顶,栈顶指针加1
return 1;
}
//出栈
int Pop(struct SqStack* S) //删除S的栈顶元素,用data返回其值
{
char ch;
if (S->top == S->base)
return 0; //栈空
--S->top;
ch = *S->top; //栈顶指针减1,将栈顶元素赋给data
return 1;
}
int StackEmpty(struct SqStack* S)
{
if (S->top != S->base)
return 0;
else
return 1;
}
char GetTop(struct SqStack* S) //返回S的栈顶元素,不修改栈顶指针
{
if (S->top != S->base)
return *(S->top - 1); //栈非空,返回栈顶元素的值
}
int main()
{
struct SqStack* S;
S = (struct SqStack*)malloc(sizeof(struct SqStack));
InitStack(S);
int flag = 1; //标记匹配结果以控制循环及返回结果
char ch;
printf("请输入()[]{},且这三种括号可以按任意次序嵌套使用,并以#结束:\n");
scanf_s("%c", &ch);
while (ch != '#' && flag) //表达式以 # 结尾
{
switch (ch)
{
case '[': //若是左括号,则将其压入栈
case '(':
Push(S, ch);
break;
case '{':
Push(S, ch);
break;
case ')': //若是右括号,则根据当前栈顶元素的值分情况考虑
if (!StackEmpty(S) && (GetTop(S) == '('))
Pop(S, GetTop(S)); //若栈非空且栈顶元素是左括号则正确匹配
else flag = 0; //若栈空或栈顶元素不是左括号则错误匹配
break;
case ']':
if (!StackEmpty(S) && (GetTop(S) == '['))
Pop(S, GetTop(S));
else flag = 0;
break;
case '}':
if (!StackEmpty(S) && (GetTop(S) == '{'))
Pop(S, GetTop(S));
else flag = 0;
break;
}
scanf_s("%c", &ch); //继续读下一个字符
}
if (StackEmpty(S) && flag)
printf("%s\n", "True");
else
printf("%s\n", "False");
return 0;
}
附:随机函数的使用(仅供参考)
#include “time.h” //用到时间函数
#include “math.h” // 用到随机函数
主程序:
time_t t; // 定义时间变量
srand((unsigned)time(&t)); //由时间确定随机序列,执行一次
生成10个随机数的循环体里:
rand()//随机生成一个0~32767的整数,可以嵌在转换公式或函数里
要求:
遇到的问题:
顺序栈在c中显示为初始化,但在c++中能正常运行。
解决:c中没有引用,初始化时应传指针。