无头单链表即为无头结点单链表其结构如下图所示
即它的首结点存放的有数据
有头结点其结构如下图所示 其首结点是不放数据的
然后我用到的读写文件的fwrite函数和fread函数想要把链表中的数据存到文件中
写文件:
void Save(LinkList L){
FILE* fp = fopen("d:/nlist.txt", "wb");
if (fp == NULL){
printf("打开存档文件失败!\n");
return ;
}
//使用fwrite往文件里写
while (L!=NULL){
fwrite(&L->data, sizeof(L->data), 1, fp);
L= L->next;
}
printf("存档成功!\n");
fclose(fp);
return;
}
读文件:
void Load(LinkList *L){
List *p=NULL,*tail=NULL;
p =tail= *L;
int i = 1;
FILE* fp = fopen("d:/nlist.txt", "r");
if (fp == NULL){
printf("打开存档文件失败\n");
return;
}
while (1){
p = (LinkList)malloc(sizeof(List));
p->next = NULL;
if (i){//使头指针指向读取的链表的头结点
size_t n = fread(&p->data, sizeof(p->data), 1, fp);
if (n == 0){//第一次读没有读到元素
free(p);
return;
}
else{
*L = p;
tail = p;
p = p->next;
}
i--;//除了第一次执行,p就不是头结点了
}
else{
size_t n = fread(&p->data, sizeof(p->data), 1, fp);
if (n == 0){
free(p);//我们是先申请空间,再把硬盘上的数据读到申请的结点空间里如果没有读到数据,
//要把最后申请的这个空间释放掉
return;
}
tail->next = p;
tail = p;
p = p->next;
}
}
}
读文件时因为要先给你读的是链表元素,要先给读到的元素分配动态的内存空间这时候就要注意:如果没读到元素记得把空间给释放掉
然后完整的代码如下图所示
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#pragma warning(disable:4996)
typedef struct nlist{
int data;
struct nlist *next;
}List, *LinkList;
void menu(){
printf(" 链表使用菜单\n");
printf("--------------------------\n");
printf("1:写入元素(头插式)\n");
printf("2:写入元素(尾插式) \n");
printf("3:查找元素所在位置 \n");
printf("4:查看链表元素个数 \n");
printf("5:插入一个元素 \n");
printf("6:删除某个元素 \n");
printf("7:按顺序打印元素 \n");
printf("0:退出 \n");
printf("--------------------------- \n");
}
void InitList(LinkList *L){
*L = NULL;
void Load(LinkList *L);
Load(L);
}//初始化完毕
void Save(LinkList L){
FILE* fp = fopen("d:/nlist.txt", "wb");
if (fp == NULL){
printf("打开存档文件失败!\n");
return ;
}
//使用fwrite往文件里写
while (L!=NULL){
fwrite(&L->data, sizeof(L->data), 1, fp);
L= L->next;
}
printf("存档成功!\n");
fclose(fp);
return;
}
void Load(LinkList *L){
List *p=NULL,*tail=NULL;
p =tail= *L;
int i = 1;
FILE* fp = fopen("d:/nlist.txt", "r");
if (fp == NULL){
printf("打开存档文件失败\n");
return;
}
while (1){
p = (LinkList)malloc(sizeof(List));
p->next = NULL;
if (i){//使头指针指向读取的链表的头结点
size_t n = fread(&p->data, sizeof(p->data), 1, fp);
if (n == 0){//第一次读没有读到元素
free(p);
return;
}
else{
*L = p;
tail = p;
p = p->next;
}
i--;//除了第一次执行,p就不是头结点了
}
else{
size_t n = fread(&p->data, sizeof(p->data), 1, fp);
if (n == 0){
free(p);//我们是先申请空间,再把硬盘上的数据读到申请的结点空间里如果没有读到数据,
//要把最后申请的这个空间释放掉
return;
}
tail->next = p;
tail = p;
p = p->next;
}
}
}
void CreateFromHead(LinkList* L){
printf("现在用头插法建立一个无头链表\n请输入要插入的元素个数\n");
int n;
scanf("%d", &n);
if (n < 1){
printf("插入元素个数错误!\n");
return ;
}
List *head;
head= (LinkList)malloc(sizeof(List));
head->next = NULL;
printf("请输入要写入的元素:\n");
scanf("%d", &head->data);
if (*L ==NULL){//使程序在建立完链表后依然可以使用头插法增加多个元素
*L = head;
}
else{
head->next = *L;
*L = head;
}
while (n-1){
head = (LinkList)malloc(sizeof(List));
head->next = NULL;
printf("请输入要写入的元素:\n");
scanf("%d", &head->data);
head->next = *L;
*L= head;
n--;
}
Save(head);
return ;
}
void CreateFromTail(LinkList *L){
printf("现在使用尾插法插入!\n");
int n;
List *tail,*p;
printf("请输入要插入的元素个数:\n");
scanf("%d", &n);
if (n < 1){
printf("输入元素个数错误!\n");
return ;
}
tail= (LinkList)malloc(sizeof(List));
tail->next = NULL;
printf("请输入要写入的元素:\n");
scanf("%d", &tail->data);
if (*L == NULL){
*L = p = tail;
}
else{
p = *L;
while (p->next != NULL){
p = p->next;
}
p->next = tail;
p = tail;
}
while (n-1){
tail= (LinkList)malloc(sizeof(List));
tail->next = NULL;
printf("请输入要写入的元素:\n");
scanf("%d", &tail->data);
p->next = tail;
p= tail;
n--;
}
Save(*L);
return ;
}
void Locate(LinkList L){
if (L == NULL){
printf("链表无元素!\n");
return ;
}
printf("请输入要查找的元素的值\n");
int tar,count=0,len =0;
List *p2[1024];//
List *p;
p = L;
scanf("%d", &tar);
while(p!=NULL){
if (p->data == tar){
p2[len] = p;
count++;
}
else{
p2[len] = NULL;
}
len++;
p = p->next;
}
printf("共有%d个元素值为%d\n分别在", count,tar);
for (int i = 0; i < len; i++){
if (p2[i] != NULL)
printf("%5d",i);
}
printf("\n");
return ;
}
void ListLen(LinkList L)
{
List *p;
p = L;
int count = 0;
while (p != NULL){
count++;
p = p->next;
}
printf("该链表共有%d个元素\n", count);
return ;
}
void InsList(LinkList *L){
if (*L == NULL){
return ;
}
printf("请输入要插入元素以及要插入的位置\n");
int data, tar,site=0;
scanf("%d %d", &data, &tar);
List *p, *back, *tarp;
p = back = *L;
tarp =( LinkList)malloc(sizeof(List));
tarp->data = data;
tarp->next = NULL;
if (tar <= 0){
printf("插入位置不合法!\n");
return ;
}
else if (tar == 1){
tarp->next = *L;
*L = tarp;
return ;
}
while (p != NULL){//p想要指向的是链表中tar-1位置处的结点
site++;
if (site == tar - 1){
break;
}
p = p->next;
if (p == NULL){
printf("插入位置不合法!big\n");
return ;
}
}
if (p->next != NULL){
back = p->next;
p->next = tarp;
tarp->next = back;
}
else{
p->next = tarp;
}
Save(*L);
return ;
}
void DelList(LinkList *L){//可能要改头指针指向的位置,因此要将头指针的地址传进函数中
if (*L == NULL){
return ;
}
List *f, *p;
p=f =* L;
printf("请输入要删除第几个元素\n");
int tar;
scanf("%d", &tar);
if (tar <= 0){
printf("删除位置错误!\n");
return ;
}
else if (tar == 1){
*L = (*L)->next;
p->next = NULL;
free(p);
return ;
}
else{
f = *L;
p =( *L)->next;
for (int i = 0; i < tar-2; i++){
if (p == NULL){
printf("删除位置错误!\n");
return ;
}
f = f->next;
p = p->next;
}
if (p->next != NULL){
f->next = p->next;
p->next = NULL;
free(p);
}
else{
f->next = NULL;
free(p);
}
Save(*L);
return ;
}
}
void PrintList(LinkList L){
system("cls");
menu();
List * p;
p = L;
while (p != NULL){
printf("%d ->", p->data);
p = p->next;
}
printf("NULL\n");
}
int main(){
LinkList L;
InitList(&L);
menu();
printf("请输入你要执行的操作序号\n");
int n;
scanf("%d", &n);
while (n){
switch (n){
case 1: CreateFromHead(&L);
break;
case 2: CreateFromTail(&L);
break;
case 3: Locate(L);
break;
case 4:ListLen(L);
break;
case 5:InsList(&L);
break;
case 6:DelList(&L);
break;
case 7:PrintList(L);
break;
default: printf("输入命令错误,请重试!\n");
break;
}
printf("请输入你要执行的操作序号\n");
scanf("%d", &n);
}
system("pause");
return 0;
}
第一次完整写一个无头单链表的完整操作代码,语法难免复杂累赘。欢迎大家的批评指正。以后我会更努力写出简洁的代码的!