2017/06/18 10:35
好多好多,学习 真非一朝一夕之功,贵在坚持,在工作即将满2年的时候,还在恶补C语言,真是罪过罪过...
数据结构、算法、文件操作、库函数应用、系统、加密解密、网络通信还有这么多东西要看,看着就头大。。。
今天来看:结构体:
实例073:定义一个结构体
struct student
{
int num;
char name[20];
float score;
};
定义结构体数组:
struct student stu[5] =
{
{
101, "liming", 89
} ,
{
102, "zhanghong", 95
}
,
{
103, "lili", 89
}
,
{
104, "weichen", 85
}
,
{
105, "yangfan", 75
}
};
实例075:比较计数
实例076:信息查询
strcmp(b[i].name,x)相等时strcmp返回0;
实例077:计算开机时间,程序报错:
网上找到调用time.h打印当前时间的方法
#include<time.h>
#include<string.h>
#include<stdio.h>
#include <conio.h>
void main()
{
char Now_time[30];
//char *t;
//t=Now_time;
//strcpy(Now_time,_strtime(t));
printf("%s",_strtime(Now_time));
_getch();
}
实例078:创建单向链表
链表包含头指针、头结点(非必须),定义链表
struct LNode
{
int data;
struct LNode *next;
};
生成一个不含头结点的链表:尾插法,传入链表长度,传出头指针;
struct LNode *create(int n)
{
int i;
struct LNode *head, *p1, *p2;
int a;
head = NULL;
printf("Input the integers:\n");
for (i = n; i > 0; --i)
{
p1 = (struct LNode*)malloc(sizeof(struct LNode)); /*分配空间*/
scanf("%d", &a); /*输入数据*/
p1->data = a; /*数据域赋值*/
if (head == NULL) /*指定头结点*/
{
head = p1;
p2 = p1;
/*printf("头指针和p2都指向新生成的指针p1");
printf("head->data=%d\n",head->data);
printf("p2->data=%d\n",p2->data);
printf("p1->data=%d\n",p1->data);*/
}
else
{
p2->next = p1; /*指定后继指针*/
p2 = p1;
/*printf("p2->data=%d\n",p2->data);
printf("p1->data=%d\n",p1->data);*/
}
}
p2->next = NULL;
return head;
}
需注意当头指针为空时,将head和p2指针都指向p1;
此创建链表的方式为在一个子函数内创建;
若生成一个含头结点的链表:
typedef struct LNode Linklist;
首先创建一个头结点,数据域一般为空,暂时就写个空字吧,
Linklist *create()
{
Linklist *head;
head=(Linklist*)malloc(sizeof(Linklist));
head->data='空';
head->next=NULL;
return head;
}
然后头插法建立链表:
Linklist *head_insert(Linklist *head,int value)
{
Linklist *p,*t;
t=head;
p=(Linklist *)malloc(sizeof(Linklist));
p->data=value;
p->next=t->next;
t->next=p;//改变t->next指针的指向;
return head;
}
头插法每次将新生成的节点插入到表头;
尾插发建立链表:
Linklist *tail_insert(Linklist *head,int value)
{
Linklist *p,*t;
t=head;
p=(Linklist *)malloc(sizeof(Linklist));
p->data=value;
while(t->next!=NULL)
t=t->next;
t->next=p;
p->next=NULL;
return head;
}
尾插法插入一个元素,效率有点低啊,每次插入一个元素,都有移动指针到末尾。
注:2017-06-27,修改,上面创建链表的方法有问题,应该用指向指针的指针而不是指针。
区别:从别处粘过来直接copy,
使用指针的地址做链表创建的输入
附:创建链表的正确方法:
以下一段引用自:《C语言–凌阳教育嵌入式–C语言》
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<conio.h>
typedef struct student
{ //数据域
int num; //学号
int score; //分数
char name[20];
struct student *next;//指针域
}STU;
void link_creat_head(STU **p_head,STU *p_new)
{
STU *p_mov=*p_head;
if(*p_head==NULL) //当第一次加入链表为空时,head执行p_new
{
*p_head=p_new;
p_new->next=NULL;
}
else //第二次及以后加入链表
{
while(p_mov->next!=NULL)
{
p_mov=p_mov->next; //找到原有链表的最后一个节点
}
p_mov->next=p_new; //将新申请的节点加入链表
p_new->next=NULL;
}
}
void link_creat_end(STU **p_head,STU *p_new)//头插法
{
STU *p_mov=*p_head;
if(*p_head==NULL) //当第一次加入链表为空时,head执行p_new
{
*p_head=p_new;
p_new->next=NULL;
}
else //第二次及以后加入链表
{
p_new->next = *p_head;
*p_head=p_new;
}
}
注:头插法需注意顺序是反的。
void link_print(STU *head)
{
STU* p_mov=head;
if(head==NULL)
printf("链表为空\n");
else
{
while(p_mov!=NULL)
{
printf("%d %d %s\n",p_mov->num,p_mov->score,p_mov->name);
p_mov=p_mov->next;
}
}
}
int main()
{
STU *head=NULL,*p_new=NULL;
int num,i;
printf("请输入链表初始个数:\n");
scanf("%d",&num);
for(i=0;i<num;i++)
{
p_new=(STU*)malloc(sizeof(STU));//申请一个新节点
printf("请输入学号、分数、名字:\n"); //给新节点赋值
scanf("%d %d %s",&p_new->num,&p_new->score,p_new->name);
link_creat_end(&head,p_new); //将新节点加入链表
}
link_print(head);
_getch();
return 0;
}
这就是传指针和传“指针的指针”的区别:
1.传指针:我们是拷贝一份地址传过去,那么对于该地址块上值的修改则会影响实参(即main()函数中的clink *h的值),但仅限于对该地址块,所以如果实参指针为空,而你在函数createclink中重新申请空间,注意这时候地址空间变了,就像你main()函数中的h依旧为空,因为函数createclink中没有对实参h的值做改变,因此,你的createclink函数没起到作用.
2.传指针的指针:这和传指针的引用效果一样,这时候值的改变中的“值”就是h,即一个地址(而上面的“传指针的值”是“该指针指向的值”),因此在createclink函数中申请空间,main()函数中h也有了新的空间,因为这种传值改变的是“地址”。
实例080:创建双向链表:
双向链表的定义为:
一个指针指向前驱,一个指针指向后继;
typedef struct node
{
char name[20];
struct node *prior,*next;
}stud;
以下为实例080稍作修改,原例子中未考虑查找元素不存在的情况;
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
typedef struct node
{
char name[20];
struct node *prior,*next;
}stud;
stud *create(int n)//创建双链表
{
stud *p,*h,*s;
int i;
h=(stud*)malloc(sizeof(stud));//注:这地方直接生成了头结点,与实例078不同,
h->name[0]='\0';
h->prior=NULL;
h->next=NULL;
p=h;
for(i=0;i<n;i++){
s=(stud*)malloc(sizeof(stud));
p->next=s;
printf("Input the %d student's: ",i+1);
scanf("%s",&(s->name));
s->prior=p;
s->next=NULL;
p=s;
}
p->next=NULL;
return (h);
}
stud *search(stud *h,char *x)//查找为x的字符,并返回链表位置
{
stud *p;
char *y;
p=h->next;
while(p)
{
y=p->name;
if (strcmp(y,x)==0){
return (p);
}
else{
p=p->next;
}
}
printf("cannot find data!\n");
return 0;
}
void del (stud *p) //删除链表的一个结点
{
p->next->prior=p->prior;//指针p的前驱
p->prior->next=p->next;//指针p的后继
free(p);
}
void main()
{
int number;
char sname[20];
stud *head,*sp;
puts("Please input the size of the list: ");
scanf("%d",&number);
head=create(number);
sp=head->next;
printf("\nNow the double list is:\n");
while(sp)
{
printf("%s ",sp->name);
sp = sp->next;
}
printf("\n Please input the name which you want to find:\n");
scanf("%s",sname);
sp=search(head,sname);
if (sp!=0){
printf("the name you want to find is :%s\n",sp->name);
/*printf("zhi=%d\n",&sp);*/
printf("zhi1=%x\n",sp);//为sp的地址
del(sp);
sp=head->next;
printf("\n Now the double list is:\n");
while(sp){
printf("%s ",sp->name);
sp=sp->next;
}
printf("\n");
puts("\n Press any key to quit...");
}
else{
printf("什么都没有");
printf("zhi1=%d\n",sp);
}
_getch();
}
调试运行结果如下:
注:上述查找链表:返回写的不好:以下做的比较好:
查找时,返回在最后,若是查找不到,返回的是NULL指针。
STU* search_name_link(STU *p_mov,char *name)
{
while(p_mov!=NULL)
{
if(strcmp(name,p_mov->name)==0)
break;
p_mov=p_mov->next;
}
return p_mov;
}
释放一个链表:使用指向指针的指针
void link_free(STU**p_head)
{
STU *temp;
while(*p_head!=NULL)
{
temp=(*p_head)->next;
free(*p_head);
*p_head=temp;
}
}
删除链表中的一个结点:
void link_delete_name(STU **p_head,char *name)
{
STU * pf,*pb;
pb=pf=*p_head;
if(*p_head==NULL)// 如果链表为空 返回NULL不需要删
{
printf("link is NULL\n");
return ;
}
while((strcmp(pb->name,name)!=0) && (pb->next!=NULL))//循环找pb的num为num的节点
{
pf=pb;//pf记录一下pb的位置
pb=pb->next;//pb指向下一个节点
}
if(strcmp(pb->name,name)==0)//找到了要删除的节点
{
if(pb==*p_head)//要删除的节点是头节点
{
*p_head=(*p_head)->next;
}
else//要删除的节点是普通节点
{
pf->next=pb->next;// pf 指向pb的下一个节点
}
free(pb);
}
else//没有节点的num为num
{
printf("没有您要删除的节点\n");
}
}
summary:除了上述链表创建、打印、查找、删除外还有:
链表的插入、排序、逆序。。。
2017/06/29 11:00
根据链表结果中的num位置插入节点到链表中:
void link_insert(STU **p_head,STU *p_new)
{
STU * pf,*pb;
pb=pf=*p_head;
if(*p_head==NULL)// 如果链表为空,则pi即为head
{
*p_head=p_new;
return ;
}
while((p_new->num >= pb->num) && (pb->next!=NULL))//循环找pb的num为num的节点
{
pf=pb;//pf记录一下pb的位置
pb=pb->next;//pb指向下一个节点
}
if(p_new->num < pb->num)//找到pb的num比p_new的num大了,p_new 插在pb的前边
{
if(pb==*p_head)//插在第一个节点的前边
{
p_new->next=*p_head;//新来的节点指向 原先的head
*p_head=p_new;//p_new 指向的节点 变成头节点
}
else//插在普通节点的前边
{
pf->next=p_new;
p_new->next=pb;
}
}
else//没有找到pb的num比pi的num大,插在链表的尾端
{
pb->next=p_new;
p_new->next=NULL;//p_new 做为尾节点
}
}
链表的排序:
相当于两重for循环遍历链表中的数值,然后按照顺序排序
STU * order(STU * head)//链表的排序
{
STU temp;
STU *pf,*pb;
pb = pf = head;
if(head == NULL)
{
printf("list is null\n");
return NULL;
}
while(pf->next!= NULL)
{
pb = pf->next;
while(pb!= NULL)
{
if(pf->num > pb->num)
{
temp = *pb;
*pb = *pf;
*pf = temp;
temp.next = pb->next;//先保存之前pb的地址
pb->next = pf->next;
pf->next = temp.next;//再将之前保存的pb的地址给pf->next
}
pb = pb ->next;
}
pf = pf->next;
}
return (head);
}
运行结果如下:
C文件下载:链表排序下载
用while循环和用for循环实质是一样的;
趁热打铁:看一下链表的逆序:
STU *reverse(STU *head)
{
STU *pf,*pb,*r;
pf=head;
pb=pf->next;
while(pb!=NULL)
{
r=pb->next;//暂存pb的下一个节点
pb->next=pf;//改变pf、pb之间的链接
pf=pb;//pf、pb重新赋值,指向下一个需要改变节点位置对
pb=r;
}
head->next=NULL;
head=pf;
return head;
}
至此:链表的创建、打印、查找、释放、删除、插入、排序、逆序代码片段全部试验完毕
实例083:约瑟夫环
循环链表实现约瑟夫环:
void Joseph(LinkList p,int m,int x){
LinkList q;
int i;
if(x==0)return;
q=p;
m%=x;
if(m==0)m=x;
for(i=1;i<=m;i++){
p=q;
q=p->next;
}
p->next=q->next;
i=q->keyword;
printf("%d ",q->keyword);
free(q);
Joseph(p,i,x-1);
}
实例084:创建顺序表并插入元素:
#define Listsize 100
struct sqlist
{
int data[Listsize];
int length;
};
void InsertList(struct sqlist *l, int t, int i)
{
int j;
if (i < 0 || i > l->length)
{
printf("position error");
exit(1);
}
if (l->length >= Listsize)
{
printf("overflow");
exit(1);
}
for (j = l->length - 1; j >= i; j--)
l->data[j + 1] = l->data[j];
l->data[i] = t;
l->length++;
}
实例085:向链表中插入节点
实例086:从链表中删除节点
实例087:合并两个链表
实例088:单链表逆置
实例089:头插法建立单链表
栈和队列
实例090:应用栈实现进制转换
栈的基本操作:构造一个空栈,判断栈空,判断栈满,进栈,出栈;取栈顶元素;
typedef struct{
DataType *base;
DataType *top;
int stacksize;
}SeqStack;
/* 置栈空*/
void Initial(SeqStack *s)
{/*构造一个空栈*/
s->base=(DataType *)malloc(STACK_SIZE * sizeof(DataType));
if(!s->base) exit (-1);
s->top=s->base;
s->stacksize=STACK_SIZE;
}
/*判栈空*/
int IsEmpty(SeqStack *S)
{
return S->top==S->base;
}
/*判栈满*/
int IsFull(SeqStack *S)
{
return S->top-S->base==STACK_SIZE-1;
}
/*进栈*/
void Push(SeqStack *S,DataType x)
{
if (IsFull(S))
{
printf("栈上溢"); /*上溢,退出运行*/
exit(1);
}
*S->top++ =x;/*栈顶指针加1后将x入栈*/
}
/*出栈*/
DataType Pop(SeqStack *S)
{
if(IsEmpty(S))
{
printf("栈为空"); /*下溢,退出运行*/
exit(1);
}
return *--S->top;/*栈顶元素返回后将栈顶指针减1*/
}
/* 取栈顶元素*/
DataType Top(SeqStack *S)
{
if(IsEmpty(S))
{
printf("栈为空"); /*下溢,退出运行*/
exit(1);
}
return *(S->top-1);
}
实例095 链队列
单链表的表首进行删除,表尾进行插入:
定义结构体:node和que
typedef struct node /*定义结点*/
{
ElemType data;/*存放元素内容*/
struct node *next;/*指向下个结点*/
}quenode;
struct quefr/*定义结点存放队首队尾指针*/
{
quenode *front,*rear;
};
初始化链队列:
void creat(struct quefr *q)/*自定义函数初始化链队列*/
{
quenode *h;
h=(quenode *)malloc(sizeof(quenode));
h->next=NULL;
q->front=h;/*队首指针队尾指针均指向头结点*/
q->rear=h;
}
元素入队列
void enqueue(struct quefr *q,int x)/*自定义函数,元素x入队*/
{
quenode *s;
s=(quenode *)malloc(sizeof(quenode));
s->data=x;/*x放到结点的数据域中*/
s->next=NULL;/*next域为空*/
q->rear->next=s;
q->rear=s;/*队尾指向s结点*/
}
元素出队列:
ElemType dequeue(struct quefr *q)/*自定义函数实现元素出队*/
{
quenode *p;
ElemType x;
p=(quenode *)malloc(sizeof(quenode));
if(q->front==q->rear)
{
printf("queue is NULL \n");
x=0;
}
else
{
p=q->front->next;
q->front->next=p->next;/*指向出队元素所在结点的后一个结点*/
if(p->next==NULL)
q->rear=q->front;
x=p->data;
free(p);/*释放p结点*/
}
return(x);
}
自定义display函数:显示队列中的元素;
void display(struct quefr dq)/*自定义函数显示队列中元素*/
{
quenode *p;
p=(quenode *)malloc(sizeof(quenode));
p=dq.front->next; /*指向第一个数据元素节点 */
while(p!=NULL)
{
printf("data=%d\n",p->data);
p=p->next;/*指向下个结点*/
}
printf("end \n");
}
实例096:循环缓冲区问题
循环队列:判断队空的条件:q->rear=q->front;
判断队满的条件:(q->rear+1) mod Maxsize ==q->front
队首队尾指针初始化
void init()/*队首队尾指针初始化*/
{
front=rear=-1;
}
这地方有疑问,循环队列初始化这地方该是front=read=0,
元素的入队列操作:
int enqueue(char x)/*元素入队列*/
{
if(front==-1&&(rear+1)==Maxsize)/*只有元素入队没有元素出队判断是否满足队满条件*/
{
printf("overflow!\n");
return 0;
}
else if((rear+1)%Maxsize==front)/*判断是否队满*/
{
printf("overflow!\n");
return 0;
}
else
{
rear=(rear+1)%Maxsize;/*rear指向下一位置*/
queue[rear]=x;/*元素入队*/
return 1;
}
}
这个实例写的真另类:队列竟然直接这样定义的:
char queue[Maxsize];
int front,rear;
真是偷工减料,写的烂不想看了,能不能走点心啊;
相关代码:元素入队列,元素出队列,取队首元素,队尾元素
……
参考:
http://www.cnblogs.com/fengberlin/p/5973404.html
http://www.cnblogs.com/zhaoyl/archive/2012/09/20/2695136.html
好了 2017/07/16 11:31
下面是串与广义表:看着都是好熟悉的名字,都怪大学没学好,现在还得艰难的拾起来。
实例097:串的模式匹配
输入主串和模式串,找到子串在主串中的位置:
定义包含字符串数组和长度的结构体
#define Maxsize 100
typedef struct/*定义结构体,用来存储串的相关信息*/
{
char string[Maxsize];
int len;
}str;/*定义str为该结构体类型*/
匹配字符串s和字符串t,并返回匹配到字符串t在主串s中的位置
int findstr(str s,str t)/*自定义函数findstr*/
{
int i=1,j=0,k=0,pos;
while(i<s.len&&j<t.len)
{
if(s.string[k]==t.string[j])/*判断主串与模式串对应元素是否匹配*/
{
k++;/*主串向后移一位*/
j++;/*模式串向后移一位*/
}
else
{/*主串和模式串重新退回,从主串的下一个位置开始下一次匹配*/
i++;
k=i;
j=0;
}
}
if(j==t.len)/*判断模式串是否已经匹配到最后一个字符*/
pos=k-j+1;/*指向匹配成功的第一个字符*/
else pos=-1;
return(pos);
}
实例099:广义表的存储:
typedef char ElemType;
typedef struct lnode
{
int tag;
union
{
ElemType data;
struct lnode *sublist;
}val;
struct lnode *next;
}GLNode;
广义表的创建:creatGList(struct lnode* *gl);
广义表的打印输出:void printGList(struct lnode *gl)
求广义表的长度:int GLLength(GLNode *gl)
求广义表的深度:int GLDepth(GLNode *gl)
实例100:广义表的复制
自定义GLCcopy函数实现广义表的复制
GLNode *GLCcopy (GLNode *gl)
求广义表的表头跟表尾
2017-08-27
实例101:二叉树
C语言数据结构精讲
本文深入探讨C语言中的数据结构实现,包括链表、栈、队列等基本概念及应用,通过具体实例讲解结构体定义、链表操作、循环队列及串处理等关键知识点。
1156

被折叠的 条评论
为什么被折叠?



