当前位置:文档之家› 081103_链表的C语言实现之单链表的实现

081103_链表的C语言实现之单链表的实现

081103_链表的C语言实现之单链表的实现
081103_链表的C语言实现之单链表的实现

链表的C语言实现之单链表的实现

https://www.doczj.com/doc/6b1925285.html,/article/2779.html

一、单链表的建立

有了动态内存分配的基础,要实现链表就不难了。

所谓链表,就是用一组任意的存储单元存储线性表元素的一种数据结构。链表又分为单链表、双向链表和循环链表等。我们先讲讲单链表。所谓单链表,是指数据接点是单向排列的。一个单链表结点,其结构类型分为两部分:

1、数据域:用来存储本身数据

2、链域或称为指针域:用来存储下一个结点地址或者说指向其直接后继的指针。

例:

typedef struct node

{

char name[20];

struct node *link;

}stud;

这样就定义了一个单链表的结构,其中char name[20]是一个用来存储姓名的字符型数组,指针*link是一个用来存储其直接后继的指针。

定义好了链表的结构之后,只要在程序运行的时候爱数据域中存储适当的数据,如有后继结点,则把链域指向其直接后继,若没有,则置为NULL。

下面就来看一个建立带表头(若未说明,以下所指链表均带表头)的单链表的完整程序。

#include <stdio.h>

#include <malloc.h> /*包含动态内存分配函数的头文件*/

#define N 10 /*N为人数*/

typedef struct node

{

char name[20];

struct node *link;

}stud;

stud * creat(int n) /*建立单链表的函数,形参n为人数*/

{

stud *p,*h,*s; /* *h保存表头结点的指针,*p指向当前结点的前一个结点,*s指向当前结点*/

int i; /*计数器*/

if((h=(stud *)malloc(sizeof(stud)))==NULL) /*分配空间并检测*/

{

printf("不能分配内存空间!");

exit(0);

}

h->name[0]='\0'; /*把表头结点的数据域置空*/

h->link=NULL; /*把表头结点的链域置空*/

p=h; /*p指向表头结点*/

for(i=0;i<n;i++)

{

if((s= (stud *) malloc(sizeof(stud)))==NULL) /*分配新存储空间并检测*/

{

printf("不能分配内存空间!");

exit(0);

}

p->link=s; /*把s的地址赋给p所指向的结点的链域,这样就把p和s所指向的结点连接起来了*/

printf("请输入第%d个人的姓名",i+1);

scanf("%s",s->name); /*在当前结点s的数据域中存储姓名*/

s->link=NULL;

p=s;

}

return(h);

}

main()

{

int number; /*保存人数的变量*/

stud *head; /*head是保存单链表的表头结点地址的指针*/

number=N;

head=creat(number); /*把所新建的单链表表头地址赋给head*/

}

这样就写好了一个可以建立包含N个人姓名的单链表了。写动态内存分配的程序应注意,请尽量对分配是否成功进行检测。

数据结构学习(C++)之单链表

节点类

【说明】因为数据结构里用到这个结构的地方太多了,如果用《数据结构》那种声明友元的做法,那声明不知道要比这个类的本身长多少。不如开放成员,事实上,这种结构只是C中的struct,除了为了方便初始化一下,不需要任何的方法,原书那是画蛇添足。下面可以看到,链表的public部分没有返回Node或者Node*的函数,所以,别的类不可能用这个开放的接口对链表中的节点操作。

【重要修改】原书的缺省构造函数是这样的Node() : data(NULL), link(NULL) {} 。我原来也是照着写的,结果当我做扩充时发现这样是不对的。当Type为结构而不是简单类型(int、……),不能简单赋NULL 值。这样做使得定义的模板只能用于很少的简单类型。显然,这里应该调用Type的缺省构造函数。这也要求,用在这里的类一定要有缺省构造函数。在下面可以看到构造链表时,使用了这个缺省构造函数。当然,这里是约定带表头节点的链表,不带头节点的情况请大家自己思考。

【闲话】请不要对int *p = new int(1);这种语法有什么怀疑,实际上int也可以看成一种class。

单链表类定义与实现

#ifndef List_H

#define List_H

#ifndef TURE

#define TURE 1

#endif

#ifndef FALSE

#define FALSE 0

#endif

typedef int BOOL;

#include "Node.h"

template class List //单链表定义

{

//基本上无参数的成员函数操作的都是当前节点,即current指的节点

//认为表中“第1个节点”是第0个节点,请注意,即表长为1时,最后一个节点是第0个节点public:

List() { first = current = last = new Node; prior = NULL; }

~List() { MakeEmpty(); delete first; }

void MakeEmpty() //置空表

{

Node *q;

while (first->link != NULL)

{

q = first->link;

first->link = q->link;

delete q;

}

Initialize();

}

BOOL IsEmpty()

{

if (first->link == NULL)

{

Initialize();

return TURE;

}

else return FALSE;

}

int Length() const //计算带表头节点的单链表长度

{

Node *p = first->link;

int count = 0;

while (p != NULL)

{

p = p->link;

count++;

}

return count;

}

Type *Get()//返回当前节点的数据域的地址

{

if (current != NULL) return ¤t->data;

else return NULL;

}

BOOL Put(Type const &value)//改变当前节点的data,使其为value

{

if (current != NULL)

{

current->data = value;

return TURE;

}

else return FALSE;

}

Type *GetNext()//返回当前节点的下一个节点的数据域的地址,不改变current

{

if (current->link != NULL) return ¤t->link->data;

else return NULL;

}

Type *Next()//移动current到下一个节点,返回节点数据域的地址

{

if (current != NULL && current->link != NULL)

{

prior = current;

current = current->link;

return ¤t->data;

}

else

{

return NULL;

}

}

void Insert(const Type &value)//在当前节点的后面插入节点,不改变current

{

Node *p = new Node(value, current->link);

current->link = p;

}

BOOL InsertBefore(const Type &value)//在当前节点的前面插入一节点,不改变current,改变prior {

Node *p = new Node(value);

if (prior != NULL)

{

p->link = current;

prior->link = p;

prior = p;

return TURE;

}

else return FALSE;

}

BOOL Locate(int i)//移动current到第i个节点

{

if (i <= -1) return FALSE;

current = first->link;

for (int j = 0; current != NULL && j < i; j++, current = current->link)

prior = current;

if (current != NULL) return TURE;

else return FALSE;

}

void First()//移动current到表头

{

current = first;

prior = NULL;

}

void End()//移动current到表尾

{

if (last->link != NULL)

{

for ( ;current->link != NULL; current = current->link)

prior = current;

last = current;

}

current = last;

}

BOOL Find(const Type &value)//移动current到数据等于value的节点

{

if (IsEmpty()) return FALSE;

for (current = first->link, prior = first; current != NULL && current->data != value;

current = current->link)

prior = current;

if (current != NULL) return TURE;

else return FALSE;

}

BOOL Remove()//删除当前节点,current指向下一个节点,如果current在表尾,执行后current = NULL {

if (current != NULL && prior != NULL)

{

Node *p = current;

prior->link = p->link;

current = p->link;

delete p;

return TURE;

}

else return FALSE;

}

BOOL RemoveAfter()//删除当前节点的下一个节点,不改变current

{

if (current->link != NULL && current != NULL)

{

Node *p = current->link;

current->link = p->link;

delete p;

return TURE;

}

else return FALSE;

}

friend ostream & operator << (ostream & strm, List &l)

{

l.First();

while (l.current->link != NULL) strm << *l.Next() << " " ;

strm << endl;

l.First();

return strm;

}

protected:

/*主要是为了高效的入队算法所添加的。因为Insert(),Remove(),RemoveAfter()有可能改变last但没有改变last所以这个算法如果在public里除非不使用这些,否则不正确。但是last除了在队列中非常有用外,其他的时候很少用到,没有必要为了这个用途而降低Insert(),Remove()的效率所以把这部分放到protected,实际上主要是为了给队列继承*/ void LastInsert(const Type &value)

{

Node *p = new Node(value, last->link);

last->link = p;

last = p;

}

void Initialize()//当表为空表时使指针复位

{

current = last = first;

prior = NULL;

}

//这部分函数返回类型为Node指针,是扩展List功能的接口Node *pGet()

{

return current;

}

Node *pNext()

{

prior = current;

current = current->link;

return current;

}

Node *pGetNext()

{

return current->link;

}

Node *pGetFirst()

{

return first;

}

Node *pGetLast()

{

return last;

}

Node *pGetPrior()

{

return prior;

}

void PutLast(Node *p)

{

last = p;

}

//这部分插入删除函数不建立或删除节点,是原位操作的接口

void Insert(Node *p)

{

p->link = current->link;

current->link = p;

}

void InsertBefore(Node *p)

{

p->link = current;

prior->link = p;

prior = p;

}

void LastInsert(Node *p)

{

p->link = NULL;

last->link = p;

last = p;

}

Node *pRemove()

{

if (current != NULL && prior != NULL)

{

Node *p = current;

prior->link = current->link;

current = current->link;

return p;

}

else return NULL;

}

Node *pRemoveAfter()

{

if (current->link != NULL && current != NULL)

{

Node *p = current->link;

current->link = current->link->link;

return p;

}

else return NULL;

}

private:

List(const List &l);

Node *first, *current, *prior, *last;

//尽量不要使用last,如果非要使用先用End()使指针last正确

};

#endif

【说明】我将原书的游标类Iterator的功能放在了链表类中,屏蔽掉了返回值为Node以及Node*类型的接口,这样的链表简单、实用,扩充性能也很好。

在完成书后作业的时候,我发现了原书做法的好处,也就是我的做法的不足。如果使用原书的定义,在完成一个功能时,只需要写出对应的函数实现。而在我的定义中,必须先派生一个类,然后把这个功能作为成员或者友元。但是这种比较并不说明书上的定义比我的要合理。首先,使用到原位操作的情况并不多,书后作业只是一种特殊情况;换句话说,书上的定义只是对完成书后作业更实用些。其次,在使用到链表的时候,通常只会用到插入、删除、取数据、搜索等很少的几个功能,我的定义足够用了。而在完成一个软件时,对链表的扩充功能在设计阶段就很清晰了,这时可以派生一个新类在整个软件中使用,对整体的规划更为有利。而对于单个链表的操作,把它作为成员函数更好理解一些。也就是说我的定义灵活性不差。

单链表应用

有人曾经建议最好把链表和链表位置这两个分开,C++标准库是这么做的;但对于初学者来说,一个类

pa, pb, p 究竟指向什么?你说这很清楚,ListNode这样的节点呗。但按照原书的定义,ListIterator::First()等等函数返回是指向data域的指针,他们怎么能直接赋值?到了下面更乱了,pb指向的区域直接分解出了Term的数据成员,也就是说是指向Term结构的;然后让ListNode类型的指针p指向这个Term结构,最后,居然把这个结构delete了,天啊,ListNode这样的节点的data域被delete了!

如果从基本的节点操作入手,谁也不会弄的这么乱。但正因为又多了一个类,很多事就疏忽了。所以,我并不怀疑标准库的做法,只是对于初学者,同一时间最好只对一个类操作。我以我的定义为基础,重新完成了这段程序。我并不欣赏原位操作的多项式加法(+),PolyA+PolyB,然后B就嗖的一下没了,A就多了一堆(也可能少了一堆);你作intJ+intK的时候怎么没见J和K有什么变化。与其这样,重载“+”还不如写成PolyA.Add(PolyB)或者PolyAdd(PolyA,PolyB)。

一元多项式类定义与实现

#ifndef Polynomial_H

#define Polynomial_H

#include "List.h"

class Term

{

public:

int coef;

int exp;

Term() : coef(0), exp(0) {}

Term(int c, int e) : coef(c), exp(e) {}

Term(int c) : coef(c), exp(0) {}

};

class Polynomial : List

{

public:

void Input()

{

cout << endl << "输入多项式的各项系数和指数";

cout << endl << "注意:请按降序输入各项,输入系数0表示结束" << endl;

int coef, exp;

for(int i = 1; ; i++)

{

cout << "第" << i << "项的系数:";

cin >> coef;

if (coef)

{

cout << "指数:";

cin >> exp;

Term term(coef, exp);

Insert(term);

}

else break;

}

}

void Print()

{

cout << endl;

First();

if (!IsEmpty())

{

Term *p = Next();

cout << p->coef;

if (p->exp)

{

cout << "x";

if (p->exp != 1) cout << "^" << p->exp;

}

while (Next() != NULL)

{

p = Get();

if (p->coef > 0) cout << "+";

cout << p->coef;

if (p->exp)

{

cout << "x";

if (p->exp != 1) cout << "^" << p->exp;

}

}

}

cout << endl;

}

friend void PolyAdd (Polynomial &polyA, Polynomial &polyB) {

Node *pA, *pB;

polyA.First();polyB.First();

pA = polyA.pNext();pB = polyB.pNext();

while (pA != NULL && pB !=NULL)

{

if (pA->data.exp == pB->data.exp)

{

pA->data.coef = pA->data.coef + pB->data.coef;

polyB.Remove();

if (!pA->data.coef) polyA.Remove();

else polyA.pNext();

}

else

{

if (pA->data.exp > pB->data.exp)

{

polyB.pRemove();

polyA.InsertBefore(pB);

}

else if (pA->data.exp < pB->data.exp) polyA.pNext();

}

pA = polyA.pGet();pB = polyB.pGet();

}

【说明】对于多项式,通常我们都是降序书写的,于是我就要求降序输入。但是对于做加法来说,确实升序的要方便一些,于是,实际上到了内部,就变成升序的了。对于输出格式(从C的时候我就不喜欢做这个),尽量照顾习惯,但是当非常数项系数为1的时候还是会输出系数的,我实在不想把一个实际应用中根本拿不出台的输出函数搞的很复杂。为我编起来方便,输出变成了升序的,请多包含。测试程序就不给了,很简单。在续篇中,我将完成一元多项式“+”“-”“×”“=”的重载——为什么没有“÷”,这种运算我拿笔算都不麻利,编起来就更闹心了,我还清楚的记得拿汇编写多字节除法程序时的痛苦。到了下一篇,你就可以这样写了a=b+c*d;a.Print()。

在下面将会有些重载运算符的例子,我们的工作将是使多项式的运算看起来更符合书写习惯。完成这些是我觉得我擅自将原书的“+”改成了PolyAdd(),总要给个交待吧。

下面将完成单链表的赋值运算的重载,请把这部分加到List类的public部分。的确,这部分也可以放在多项式类里实现;但是,复制一个多项式实际上就是复制一个单链表,与其单单做一个多项式赋值,还不如

还记得List类的private里面的这个List(const List &l)吗?当初怕它惹祸,直接将它禁用了,既然现在=都能用了,为了这种语法List b = a;顺便也把它完成了吧。现在可以把它从private放到public 了。

终于可以这样写了a = b + c * d

friend Polynomial operator + (Polynomial &polyA, Polynomial &polyB)

{

Polynomial tempA = polyA;Polynomial tempB = polyB;

PolyAdd(tempA, tempB);

return tempA;

}

friend Polynomial operator * (Polynomial &polyA, Polynomial &polyB)

{

Node *pA = polyA.pGetFirst()->link;

Node *pB = polyB.pGetFirst()->link;

Polynomial polyTempA, polyTempB;

int coef, exp;

if (pA == NULL || pB == NULL) return polyTempA;

for (pA = polyA.pGetFirst()->link; pA != NULL; pA = pA->link)

{

for(pB = polyB.pGetFirst()->link; pB != NULL; pB = pB->link)

{

coef = pA->data.coef * pB->data.coef;

exp = pA->data.exp + pB->data.exp;

Term term(coef, exp);

https://www.doczj.com/doc/6b1925285.html,stInsert(term);

}

PolyAdd(polyTempA, polyTempB);

polyTempB.Initialize();

}

return polyTempA;

}

【后记】很显然,在“+”的处理上我偷懒了,但这是最方便的。乘法部分只要参照手工运算,还是很简单的,我就不解释了。对于“-”,可以先完成(-a)这样的算法,然后就可以用加法完成了,而你要是象我一样懒很可能就会做这种事-a=-1×a,真的不提倡,超低的效率。对于除法,如果你会用汇编写多字节除法(跟手工计算很像),依样画葫芦也能弄出来,但首先要完成“-”。如果要写又得好长,留给你完成吧。到这里你明白原位加法的重要了吧,这些运算实际上都是靠它实现的。

C语言链表的建立、插入和删除

数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性。但数组也同样存在一些弊病。如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个大小的数组,有时需要5 0个数组的大小,难于统一。我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费。我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要。链表就是我们需要的动态数组。它是在程序的执行过程中根据需要有数据存储就向系统要求申请存储空间,决不构成对存储区的浪费。 链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表,下面将逐一介绍。 7.4.1 单链表 图7 - 3是单链表的结构。 单链表有一个头节点h e a d,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型,节点有两个成员:整型成员(实际需要保存的数据)和指向下一个结构体类型节点的指针即下一个节点的地址(事实上,此单链表是用于存放整型数据的动态数组)。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为N U L L。 图7 - 3还给出这样一层含义,链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。 看一下链表节点的数据结构定义: struct node { int num; struct node *p; } ; 在链表节点的定义中,除一个整型的成员外,成员p是指向与节点类型完全相同的指针。在链表节点的数据结构中,非常特殊的一点就是结构体内的指针域的数据类型使用了未定义成功的数据类型。这是在C中唯一规定可以先使用后定义的数据结构。 ?单链表的创建过程有以下几步: 1 ) 定义链表的数据结构。 2 ) 创建一个空表。 3 ) 利用m a l l o c ( )函数向系统申请分配一个节点。 4 ) 将新节点的指针成员赋值为空。若是空表,将新节点连接到表头;若是非空表,将新 节点接到表尾。 5 ) 判断一下是否有后续节点要接入链表,若有转到3 ),否则结束。 ?单链表的输出过程有以下几步 1) 找到表头。

C语言链表功能实现

#include #define MaxSize 10 #define error 0 typedef int ElemType; typedef struct{ ElemType elem[MaxSize]; int last; }SeqList; void Input(SeqList *L);//Input the list void Output(SeqList L);//Output the list void Search(SeqList L);//Search element void Insert(SeqList *L); void Delete(SeqList *L); void Sort(SeqList *L); void bubblesort(SeqList *L); void selectsort(SeqList *L); void Function(); int main(){ int i,flag=1,k; ElemType e; SeqList L; https://www.doczj.com/doc/6b1925285.html,st=0; Function(); printf("Please pick an option: "); scanf("%d",&k); while(flag){ switch(k){ case 0:{ flag=0; break; } case 1:{ Input(&L); break; } case 2:{ Output(L); break; } case 3:{ Insert(&L); break; } case 4:{

Search(L); break; } case 5:{ Delete(&L); break; } case 6:{ bubblesort(&L); break; } case 7:{ selectsort(&L); break; } default :{ printf("\nOption is useless.Please input again."); break; } } if(flag){ printf("\nPlease pick an option: "); scanf("%d",&k); } } return 0; } void Input(SeqList *L){ int i,n; printf("Please input the sum of elements:\n"); scanf("%d",&n); while(n>MaxSize){ printf("Sum is bigger than MaxSize,please input again\n"); scanf("%d",&n); } printf("Input the elements of list:\n"); for(i=0;ielem[i]); L->last++; } } void Output(SeqList L){

C语言链表专题复习

链表专题复习 数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性。但数组也同样存在一些弊病。如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个元素大小的数组,有时需要5 0个数组元素的大小,难于统一。我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费。 我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要。链表就是我们需要的动态数组。它是在程序的执行过程中根据需要有数据存储就向系统要求申请存储空间,决不构成对存储区的浪费。 链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表,下面只介绍单向链表。 7.4.1 单链表 图7 - 3是单链表的结构。 单链表有一个头节点h e a d,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型,节点有两个成员:整型成员(实际需要保存的数据)和指向下一个结构体类型节点的指针即下一个节点的地址(事实上,此单链表是用于存放整型数据的动态数组)。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为N U L L。 图7 - 3还给出这样一层含义,链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。 看一下链表节点的数据结构定义: struct node { int num; struct node *p; } ; 在链表节点的定义中,除一个整型的成员外,成员p是指向与节点类型完全相同的指针。 在链表节点的数据结构中,非常特殊的一点就是结构体内的指针域的数据类型使用了未定义成功的数据类型。这是在C中唯一规定可以先使用后定义的数据结构。 ?单链表的创建过程有以下几步: 1 ) 定义链表的数据结构。 2 ) 创建一个空表。 3 ) 利用m a l l o c ( )函数向系统申请分配一个节点。

数据结构(C语言)单链表的基本操作

实验名称:实验一单链表的基本操作 实验目的 熟练掌握线性表两类存储结构的描述方法。 实验内容 从键盘读入若干个整数,建一个整数单链表,并完成下列操作: (1)打印该链表; (2)在链表中插入一个结点,结点的数据域从键盘读入,打印该链表; (3)在链表中删除一个结点,被删结点的位置从键盘读入,打印该链表; (4)在链表中做查找:从键盘读入要查找的整数,将该整数在链表中的位置打印出来,若要查找的整数不在链表中,返回一个信息。 算法设计分析 (一)数据结构的定义 单链表存储结构定义为: struct Node; typedef struct Node * pnode; struct Node { int info; pnode link; }; typedef struct Node * LinkList; (二)总体设计 程序由主函数、创建单链表函数、链表长度函数、链表打印函数、插入正整数函数、删除函数、查询函数组成。其功能描述如下: (1)主函数:调用各个函数以实现相应功能 int main(void) //主函数 { printf("单链表的基本操作实验:\n"); struct list *pnode; pnode = creat(); //创建 print(pnode); //输出 insert(pnode); //插入 print(pnode); //输出 _delete(pnode); //删除 print(pnode); //输出 _located(pnode); //查找 print(pnode); //输出 return 0 ; } (三)各函数的详细设计: Function1: struct list *creat()//创建链表;

单链表的建立及插入删除操作-c语言

单链表的基本操作 #include #include typedef char date; typedef struct node { date ch; struct node *next; }list; typedef list *linklist; linklist creat() { date ch; linklist head=(linklist)malloc(sizeof(list)); list *p,*r; r=head; ch=getchar(); while(ch!='\n') { p=(linklist)malloc(sizeof(list)); p->ch=ch; r->next=p; r=p; ch=getchar(); } r->next=NULL; return (head); } void insert(linklist head,int i,char x) { int j=0; linklist r,p; p=head->next; while(p&&jnext; j++; } if(!p||j>i-1) exit(1); r=(linklist)malloc(sizeof(list)); r->ch=x;

r->next=p->next; p->next=r; } void puter(linklist linker) { linklist p; p=linker->next; while(p!=NULL) { printf("%c ",p->ch); p=p->next; } } void delet(linklist head ,int i) { int j=0; linklist r,p; p=head->next; while(p&&jnext; j++; } if(!p||j>i-1) exit(1); r=p->next; p->next=r->next; free(r); } int main() { static int q,k; char w; printf("请输入字符穿,并以ENTER键结束\n"); linklist head,p,linker=creat(); puter(linker); printf("请输入插入位置和插入字母\n"); scanf("%d %c",&q,&w); insert(linker,q,w); puter(linker); printf("\n请输入删除位置的序号:\n"); scanf("%d",&k); delet(linker,k);

C语言课程设计_职工信息管理系统_单链表实现程序源代码

//C语言课程设计职工信息管理系统—单链表实现 #include "stdio.h" #include "stdlib.h" #include "string.h" int saveflag=0; /*是否需要存盘的标志变量*/ struct employee { char name[15]; char num[10];/* 工号 */ char sex[4]; char bm[15]; char zc[20]; int gz; }; typedef struct node { struct employee data; struct node *next; }Node,*Link; //Link l (注意是:字母l不是数字1) void add(Link l); void disp(Link l); //查看职工所有信息 void del(Link l); //删除功能 Node* Locate(Link l,char findmess[],char nameornum[]); void Qur(Link l); //查询功能 void Tongji(Link l); //统计 void Sort(Link l); //排序 void Modify(Link l); //修改功能 void save(Link l); //将单链表l中的数据写入文件 void printe(Node *p); //本函数用于打印链表中某个节点的数据内容 */ //以下4个函数用于输出中文标题 void printstart(); void Wrong(); void Nofind(); void printc();

单链表完整C语言纯代码

单链表 带头结点 #include #include /* 带头结点的单链表的操作 在该链表中,数据元素是int, 我们让头结点的数据域存储链表的实际长度 */ /*链表节点的类型定义*/ struct node { int data; struct node *next; }; /* 链表的初始化函数 在该函数中要分配头结点存储空间 让头指针指向头结点, 因此要修改头指针的值, 所以传递头指针的地址进来 */ void init(struct node **h) { struct node *s; s = (struct node *)malloc(sizeof(struct node)); if(s==NULL) return; /* 头结点的数据域存储链表的长度 */ s->data=0; s->next=NULL; /*让头指针指向头结点*/ *h = s; } /* 创建链表,仍然按照逆序创建, 从后往前输入元素的值, 然后把新结点插入到表头 */ void createLink(struct node *h) {

struct node *s; int n; while(1) { scanf("%d",&n); /*根据实际情况判断链表的元素 输入结束 还有一种情况就是找不到合适的 作为结束标记的值 先让用户输入元素个数, 然后固定字数循环*/ if(n==-1) break; /* 创建新结点 */ s = (struct node *)malloc(sizeof(struct node)); s->data = n; s->next = h->next; /* 新结点放入链表的表头 让头结点的NEXT指向新结点 */ h->next = s; (h->data)++; } } /* 遍历整个链表 */ void bianliLink(struct node *h) { int k; struct node *p; /* P指向第一个结点 */ p=h->next; /* 如果定义了链表长度变量, 可以使用变量计数, 表示处理到链表的最后一个元素 如果不定义链表长度变量, 就用指针是否指向NULL, 判断是否处理到最后一个元素了

C语言程序设计-基于链表的学生成绩管理系统

华北科技学院计算机系综合性实验 实验报告 课程名称 C语言程序设计 实验学期 2011 至 2012 学年第二学期学生所在系部计算机系 年级 2011 专业班级计算机科学与技术B-111 学生姓名学号 任课教师 实验成绩 计算机系制

实验报告须知 1、学生上交实验报告时,必须为打印稿(A4纸)。页面空间不够,可以顺延。 2、学生应该填写的内容包括:封面相关栏目、实验地点、时间、目的、设备环境、 内容、结果及分析等。 3、教师应该填写的内容包括:实验成绩、教师评价等。 4、教师根据本课程的《综合性实验指导单》中实验内容的要求,评定学生的综合 性实验成绩;要求在该课程期末考试前将实验报告交给任课教师。综合性实验中,所涉及的程序,文档等在交实验报告前,拷贝给任课教师。任课教师统一刻录成光盘,与该课程的期末考试成绩一同上交到系里存档。 5、未尽事宜,请参考该课程的实验大纲和教学大纲。

《C语言程序设计》课程综合性实验报告 实验题目基于链表的学生成绩管理系统 一、实验目的 1、掌握链表的创建、遍历显示和清除; 2、掌握链表数据的文件保存、读取; 二、设备与环境 微型计算机、VC++ 三、实验内容 1、定义结构体,创建链表 struct xsnode { int xh; char xm[15]; int gs; int yy; int wl; struct xsnode *next; }; 2、根据以上链表结点结构,实现以下功能 a、学生学号、姓名、各门成绩的录入; b、链表数据显示及清除; c、链表数据的文件保存与读取; 四、实验结果及分析 1、运行结果 主菜单

081103_链表的C语言实现之单链表的实现

链表的C语言实现之单链表的实现 https://www.doczj.com/doc/6b1925285.html,/article/2779.html 一、单链表的建立 有了动态内存分配的基础,要实现链表就不难了。 所谓链表,就是用一组任意的存储单元存储线性表元素的一种数据结构。链表又分为单链表、双向链表和循环链表等。我们先讲讲单链表。所谓单链表,是指数据接点是单向排列的。一个单链表结点,其结构类型分为两部分: 1、数据域:用来存储本身数据 2、链域或称为指针域:用来存储下一个结点地址或者说指向其直接后继的指针。 例: typedef struct node { char name[20]; struct node *link; }stud; 这样就定义了一个单链表的结构,其中char name[20]是一个用来存储姓名的字符型数组,指针*link是一个用来存储其直接后继的指针。 定义好了链表的结构之后,只要在程序运行的时候爱数据域中存储适当的数据,如有后继结点,则把链域指向其直接后继,若没有,则置为NULL。 下面就来看一个建立带表头(若未说明,以下所指链表均带表头)的单链表的完整程序。 #include <stdio.h> #include <malloc.h> /*包含动态内存分配函数的头文件*/ #define N 10 /*N为人数*/ typedef struct node { char name[20]; struct node *link; }stud; stud * creat(int n) /*建立单链表的函数,形参n为人数*/ { stud *p,*h,*s; /* *h保存表头结点的指针,*p指向当前结点的前一个结点,*s指向当前结点*/ int i; /*计数器*/ if((h=(stud *)malloc(sizeof(stud)))==NULL) /*分配空间并检测*/ { printf("不能分配内存空间!"); exit(0); } h->name[0]='\0'; /*把表头结点的数据域置空*/ h->link=NULL; /*把表头结点的链域置空*/ p=h; /*p指向表头结点*/ for(i=0;i<n;i++) {

单链表完整C语言纯代码

单链表完整C语言纯代码

单链表 带头结点 #include #include /* 带头结点的单链表的操作 在该链表中,数据元素是int, 我们让头结点的数据域存储链表的实际长度*/ /*链表节点的类型定义*/ struct node { int data; struct node *next; }; /* 链表的初始化函数 在该函数中要分配头结点存储空间 让头指针指向头结点, 因此要修改头指针的值, 所以传递头指针的地址进来 */

void init(struct node **h) { struct node *s; s = (struct node *)malloc(sizeof(struct node)); if(s==NULL) return; /* 头结点的数据域存储链表的长度 */ s->data=0; s->next=NULL; /*让头指针指向头结点*/ *h = s; } /* 创建链表,仍然按照逆序创建, 从后往前输入元素的值, 然后把新结点插入到表头 */ void createLink(struct node *h) { struct node *s;

int n; while(1) { scanf("%d",&n); /*根据实际情况判断链表的元素 输入结束 还有一种情况就是找不到合适的 作为结束标记的值 先让用户输入元素个数, 然后固定字数循环*/ if(n==-1) break; /* 创建新结点 */ s = (struct node *)malloc(sizeof(struct node)); s->data = n; s->next = h->next; /* 新结点放入链表的表头 让头结点的NEXT指向新结点 */

C语言中链表的创建

C语言数据类型的使用 struct student //这里struct是保留字,student是结构体名;它们合起来就是结构体类型名{ int num; char name[20]; char sex; int age; float score; char addr[30]; }; //{}之间是结构体成员表 struct student student1, student2; //用以上的结构体类型名定义两个变量 struct student stu[20]; //用以上的结构体类型名定义一个20个元素的数组 以上说明也可缩写成: struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }student1, student2, stu[20]; 使用typedef定义类型 typedef struct { int num; char name[20]; char sex; int age; float score; char addr[30]; }STUDENT; //定义一个结构类型名 STUDENT student1, student2, stu[20]; //用结构类型名定义变量 结构变量的引用 student1.num=12; https://www.doczj.com/doc/6b1925285.html,=”马大哈”; stu[10].score=88; stu[1].sex=’M’; student1.addr=”北京市丰台区富丰路7号”; 看typedef的使用 typedef int INTEGER; typedef float REAL; typedef int ARR[10];

链表的C语言实现

链表的C语言实现 分类:计算机学习 2006.12.29 09:06 作者:ybxycy | 评论:0 | 阅读:652 数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性。但数组也同样存在一些弊病。如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个大小的数组,有时需要5 0个数组的大小,难于统一。我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费。 我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要。链表就是我们需要的动态数组。它是在程序的执行过程中根据需要有数据存储就向系统要求申请存储空间,决不构成对存储区的浪费。 链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表,下面将逐一介绍。 7.4.1 单链表 图7 - 3是单链表的结构。 单链表有一个头节点h e a d,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型,节点有两个成员:整型成员(实际需要保存的数据)和指向下一个结构体类型节点的指针即下一个节点的地址(事实上,此单链表是用于存放整型数据的动态数组)。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为N U L L。 图7 - 3还给出这样一层含义,链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。

C语言实现单链表逆置

什么单链表的逆置 问题描述 设计一个程序,实现单链表的逆置。 一、需求分析 ⑴按程序提示输入并创建一个单链表,带有头结点 ⑵可自定义链表的长度,可自定义链表储存的数据类型,注意更改相应的输入输出方式 ⑶实现单链表的逆置,直观地输出结果 二、概要设计 为实现上述程序功能,需创建以下抽象数据类型: ADT LinkList { 数据对象:D={ai|ai∈(0,1,…,9),i=0,1,2,…,n,n≥0} 数据关系:R={|ai-1,ai∈D,i=1,2,…,n} 基本操作: InitList(&L) 操作结果:初始化一个链表L。 CreatList(L,L_Length) 初始条件:链表L已存在。 操作结果:创建一个长度为L_Length的单链表。 InverseList(L) 初始条件:链表L已存在。 操作结果:将单链表逆置。 DisplayList(L) 初始条件:链表L已存在。 操作结果:销毁链表L。 } ADT LinkList 本程序包含四个模块,即 1)主程序模块,接受命令 2)初始化及链表创建模块,按要求创建链表 3)单链表逆置模块,实现单链表的逆置 4)显示模块,输出结果 三、详细设计(C语句,而非伪码) 1.元素类型、节点类型和指针类型的定义 typedef int Status;//函数状态类型

typedef int ElemType;//元素类型 typedef struct node{ ElemType data; struct node *next; }Node,*LinkList;//节点类型、 2.基本操作和所需调用的函数 //初始化一个链表 Status InitList(LinkList *L) { *L=(LinkList)malloc(sizeof(node)); if(!(*L)) exit(-2);//内存分配失败 (*L)->next=NULL; return 1; } //在初始化的基础上按顺序创建一个链表 Status CreatList(LinkList L,int n) { LinkList p=L; int i; for(i=0;inext)=(LinkList)malloc(sizeof(node)); if (!(p->next)) exit(-2);//内存分配失败 scanf("%d",&p->next->data); p=p->next; } p->next=NULL; return 1; } //依次输出单链表中的各个元素 Status DisplayList(LinkList L) { LinkList p; p=L->next; while(p) { printf("%5d",p->data); p=p->next;

链表的C语言实现之单链表的查找运算

建立了一个单链表之后,如果要进行一些如插入、删除等操作该怎么办?所以还须掌握一些单链表的基本算法,来实现这些操作单链表的基本运算包括:查找、插入和删除下面我们就一一介绍这三种基本运算的算法,并结合我们建立单链表的例子写出相应的程序 1、查找 对单链表进行查找的思路为:对单链表的结点依次扫描,检测其数据域是否是我们所要查好的值,若是返回该结点的指针,否则返回null 因为在单链表的链域中包含了后继结点的存储地址,所以当我们实现的时候,只要知道该单链表的头指针,即可依次对每个结点的数据域进行检测 以下是应用查找算法的一个例子: #include <stdio.h> #include <malloc.h> #include <string.h>/*包含一些字符串处理函数的头文件*/ #define n 10 typedef struct node { char name[20]; struct node *link; }stud; stud * creat(int n) /*建立链表的函数*/ { stud *p,*h,*s; int i; if((h=(stud *)malloc(sizeof(stud)))==null) { printf(\"不能分配内存空间!\"); exit(0); } h->name[0]=\'\\0\'; h->link=null; p=h; for(i=0;i<n;i++) { if((s= (stud *) malloc(sizeof(stud)))==null) { printf(\"不能分配内存空间!\"); exit(0); } p->link=s;

单链表数据结构C语言

单链表的建立(头插法) 写一算法用头插法建立无头结点的单链表,结果返回单链表的头指针typedef char DataType; typedef struct node{ DataType data; struct node *next;}ListNode; typedef ListNode *LinkList; LinkList CreateListF(void) { char ch; LinkList head; ListNode *s; head=NULL; ch=getchar(); while(ch!='\n') {s=(ListNode*)malloc(sizeof(ListNode)); s->data=ch; s->next=head; head=s; ch=getchar(); } return(head); } 单链表的打印 写一算法打印不带头结点的单链表head中每个结点的值 typedef char DataType; typedef struct node{ DataType data; struct node *next;}ListNode; typedef ListNode *LinkList; void PrintList(LinkList head) {ListNode *p; for(p=head;p;p=p->next) printf("%c",p->data); printf("\n"); } 单链表的建立(尾插法) 写一算法用尾插法建立无头结点的单链表,结果返回单链表的头指针typedef char DataType; typedef struct node{ DataType data; struct node *next;}ListNode;

C语言课程设计职工信息管理系统单链表实现程序源代码

C语言课程设计职工信息管理系统单链表实现 程序源代码 文档编制序号:[KKIDT-LLE0828-LLETD298-POI08]

有%d条记录已经保存.)\n",count); saveflag=0; } else { system("cls"); printf("保存文件失败,'0'条记录被保存!\n"); } fclose(fp); } xt","ab+"); else exit(0); } ....\n"); while(!feof(fp)) n",count); while(1) { menu(); printf("\t\t====>请选择:"); scanf("%d",&choose); if(choose==0) { if(saveflag==1) { getchar(); printf("\n=====>提示:资料已经改动,是否将改动保存到文件中(y/n)\n"); scanf("%c",&ch); if(ch=='y'||ch=='Y') Save(list); } //if printf("\n=====>提示:你已经退出系统,再见!\n"); break; }//if switch(choose) { case 1:Add(list); break; /* 增加职工记录 */

case 2: Del(list); break;/* 删除职工记录 */ case 3: Qur(list); break;/* 查询职工记录 */ case 4: Modify(list); break;/* 修改职工记录 */ case 5: Insert(list); break;/*插入职工记录*/ case 6: Tongji(list); break;/*统计职工记录*/ case 7: Sort(list); break;/*排序职工记录*/ case 8: Save(list); break;/* 保存职工记录 */ case 9: system("cls"); Disp(list); break; /*显示职工记录*/ default: Wrong(); getchar(); break; } //switch(choose) }//while(1) } //main() /* */

C语言 创建一个链表

C语言创建一个链表,并将数据倒序输出 代码如下: #include #include #include #define ok 1 #define Elemtype int typedef int status; typedef struct sql { Elemtype length; Elemtype data; struct sql *next; }SQL; SQL L; SQL *head; status create_head() //创建头结点 { head=(SQL *)malloc(sizeof(struct sql)); head->next=NULL; if(head) return ok; } status create_sql() //创建链表,并输入数据 { int a,i; SQL *p,*q; p=head; printf("\n请输入链表的长度:"); scanf("%d",&a); L.length=a; for(i=1;i<=L.length;i++) { q=(SQL *)malloc(sizeof(SQL)); if(q) { printf("第%d个节点创建成功,请输入数据:",i); scanf("%d",&q->data); p->next=q; p=q; q->next=NULL; } else

{ printf("节点未创建成功,程序正在退 出"); exit(0); } } return ok; } status output() //输出链表的数据 { SQL *p; p=head->next; while(p) { printf("%4d",p->data); p=p->next; } return ok; } status daoxu() //将链表的数据倒序 { SQL *k,*p,*q; int flag,i; //flag 标志位记录当前 *q 所在的节点 flag=0 为q指 向头结点 p=head->next; for(i=1;inext; } else { printf("链表为空!"); exit(0); } } k=p; //*k 保存了最后一个节点的地址 flag=--i; while(flag) {

c语言程序设计报告链表实现学生信息管理

C语言课程设计报告 链表实现学生信息管理

一.课程设计目标 C语言课程设计的目的是通过课程设计的综合训练,培养学生实际分析问题、编程和动手能力,最终目标是通过这种形式,帮助学生系统掌握该门课程的主要容,更好地完成教学任务。本课程设计具有如下特点:重点在于C语言的基本特征上,涵盖了C语言的重要基础知识。结合了实际应用的要求,使课程设计既涵盖知识点,又接近工程实际需要。通过激发学习兴趣,调动学生主动学习的积极性,并引导他们根据实际编程要求,训练自己实际分析问题的能力以及编程能力,并养成良好的编程习惯。 另外,在实际编程中,为了提高编程质量,希望学生在书写代码时,对空行、空格和注释严格按要求处理,以建立良好的编程风格。 二.设计项目:学生学籍管理 该课程设计是设计一个模拟学生信息管理程序,要求使用链表来实现。它具有浏览、插入、删除、修改等功能,并且能够对数据进行文件存储和读出操作。 主要功能模块: 1. 浏览学生信息:显示学生的信息。 2. 插入学生信息:添加学生的信息。 3. 删除学生信息:通过输入学号删除学生的信息。 4. 修改学生信息:通过输入学号修改学生的信息。 5. 保存学生信息:将学生信息保存到文件。 0. 退出系统:结束程序的运行,结束前询问是否保存信息。

三.具体任务 由老师提供主菜单程序以及第0、2个模块。 学生在这个信息系统中加入四个模块,即: 1. 浏览学生信息 3. 删除学生信息 4. 修改学生信息 5. 保存学生信息

四、详细介绍 1、浏览学生信息 2、插入学生信息

3、删除学生信息 4、修改学生信息

链表的c语言实现(一)

链表的c语言实现(一) 准备:动态内存分配 一、为什么用动态内存分配 但我们未学习链表的时候,如果要存储数量比较多的同类型或同结构的数据的时候,总是使用一个数组。比如说我们要存储一个班级学生的某科分数,总是定义一个float型(存在0.5分)数组: float score[30]; 但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大? 在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道该班级的学生的人数,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道该班级的学生数,但是如果因为某种特殊原因人数有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。 那么有没有其它的方法来解决这样的外呢体呢?有,那就是动态内存分配。 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。从以上动、静态内存分配比较可以知道动态内存分配相对于景泰内存分配的特点: 1、不需要预先分配存储空间; 2、分配的空间可以根据程序的需要扩大或缩小。 二、如何实现动态内存分配及其管理 要实现根据程序的需要动态分配存储空间,就必须用到以下几个函数 1、malloc函数 malloc函数的原型为: void *malloc (unsigned int size)

严蔚敏版数据结构建立学生信息单链表C语言版适合VC++

#include #include #include typedef struct Student/*定义学生类*/ { int num; char name[20]; char sex[2]; int age; float grade; }stu; typedef struct LNode { stu data; struct LNode *next; }LNode,* Linklist; Linklist InitList_L(Linklist L)/*构造一个空的单向链表*/ { L=(Linklist)malloc(sizeof(stu)); if(!L) printf("ERROR\n"); else { L=NULL; printf("OK\n"); return L; } } void DestroyList_L(Linklist L)//销毁单向链表*/ { Linklist p; if(!L) printf("ERROR\n"); else { while(L) { p=L; L=L->next; free(p); } printf("OK\n"); } }

void ClearList_L(Linklist L)/*将L重置为空表*/ { Linklist p; if(!L) printf("ERROR\n"); else { while(L->next) { p=L->next; L->next=p->next; free(p); } printf("OK\n"); } } void ListEmpty_L(Linklist L)/*L为空表返回TRUE,否则返回FALSE*/ { if(!L) printf("ERROR\n"); else { if(!L->next) printf("TRUE\n"); else printf("FLASE\n"); } } int ListLength_L(Linklist L)/*返回L中数据元素个数*/ { int i=0; Linklist p=L; if(!L) return 0; else { while(p) { i++; p=p->next; } return i; } }

单链表的基本操作 C语言课程设计

课程设计(论文) 题目名称单链表的基本操作 课程名称C语言程序课程设计 学生姓名 学号 系、专业信息工程系、网络工程专业 指导教师成娅辉 2013年6月6 日

目录 1 前言 (3) 2 需求分析 (3) 2.1 课程设计目的 (3) 2.2 课程设计任务 (3) 2.3 设计环境 (3) 2.4 开发语言 (3) 3 分析和设计 (3) 3.1 模块设计 (3) 3.2 系统流程图 (4) 3.3 主要模块的流程图 (6) 4 具体代码实现 (9) 5 课程设计总结 (12) 5.1 程序运行结果 (12) 5.2 课程设计体会 (12) 参考文献 (13) 致谢 (13)

1 前言 我们这学期学习了开关语句,循环语句、链表、函数体、指针等的应用,我们在完成课程设计任务时就主要用到这些知识点,本课题是单链表的简单操作,定义四个子函数分别用来创建链表、输出链表、插入数据以及删除数据,主函数中主要用到开关语句来进行选择调用哪个子函数,下面就是课程设计的主要内容。 2 需求分析 2.1 课程设计目的 学生在教师指导下运用所学课程的知识来研究、解决一些具有一定综合性问题的专业课题。通过课程设计(论文),提高学生综合运用所学知识来解决实际问题、使用文献资料、及进行科学实验或技术设计的初步能力,为毕业设计(论文)打基础。 2.2 课程设计任务 输入一组正整数,以-1标志结束,用函数实现:(1)将这些正整数作为链表结点的data域建立一个非递减有序的单链表,并输出该单链表;(2)往该链表中插入一个正整数,使其仍保持非递减有序,输出插入操作后的单链表;(3)删除链表中第i个结点,输出删除操作后的单链表,i从键盘输入。 2.3 设计环境 (1)WINDOWS 7系统 (2)Visual C++ 2.4 开发语言 C语言 3 分析和设计 3.1 模块设计 定义链表结点类型struct node表示结点中的信息,信息包括数据域data(用于存放结点中的有用数据)以及指针域next(用于存放下一个结点的地址),并将链表结点类型名改为NODE。如下所示:

相关主题
文本预览
相关文档 最新文档