单链表和顺序表都是线性表,其外在操作完全一致。唯一的差异就在存储结构上,就是这点差异导致了迥然不同的代码实现。话不多说,赶紧上车吧!
运行效果图:
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);
}
}