您的位置:首页 > 理论基础 > 数据结构算法

【数据结构郝斌】3、模块一:线性结构

2017-02-27 11:03 106 查看
1、连续存储(数组)

 int a[10];
 int *pArr = (*int


 1)什么叫数组

  元素类型相同,大小相等。

 2)数组的优缺点

  优点:存取速度快

  缺点:事先必须知道数组的长度,插入删除元素慢,空间通常是有限制,需要大块连续内存。

  练习代码见:数据结构数组算法.c

 确定一个数组需要几个信息:

  数组首地址

  数组长度

  有效位数

2、离散存储(链表)

 1)链表优缺点:

  优点:空间没有限制,插入删除元素快

  缺点:存取速度很慢。

 2)预备知识:typedef的用法:

typedef struct Student
{
int sid;
char name[100];
char sex;
}*PST,ST;   //ST等价于struct Student,PST等价于:struct Student *
//给 struct Student类型的指针PST
//此时PST等价于:struct Student * 是一个指针


  树与图都是靠链表实现的,所以,链表非常重要。

 3)定义:

  n个节点离散分配

  彼此通过指针相连

  每个节点只有一个前去节点,每个节点只有一个后续节点。

  首节点没有前驱结点,尾节点没有后续节点。

  专业术语:

   首节点:

    第一个有效节点

   尾节点:

    最后一个有效节点,指向下一个元素的指针为空。

   头节点:

    头节点数据类型与首节点数据类型相同

    第一个有效节点前的节点

    不存放有效数据

    目的主要是为了方便对链表的操作。

   头指针:

    指向头结点的指针变量

   尾指针:

    指向尾节点的指针变量

  如果希望通过一个函数来对链表进行处理,我们至少徐亚接收链表的那些参数(确定一个链表需要几个参数):

   只需要一个参数:头指针

   因为我们通过头指针可以推算出链表的其他所有信息。

  链表的定义:

typedef struct Node
{
int data;               //数据域

struct Node *pNext; //指针
}NODE,*PNODE;           //NODE等价于struct Node, PNODE等价于struct Node *


 4)分类:

  单链表:

  双链表:

   每个节点有两个指针域,指向前一个与后一个节点。

  循环链表:

   能通过任何一个节点找到其他所有的节点。

  非循环链表:

 5)算法:

  遍历

  查找

  清空

  销毁

  求长度

  排序

  删除节点:



p->pNext = p->pNext->pNext; //内存泄漏(p后边节点的内存没释放)

不能free(p->pNext);
正确做法:
r = p->pNext;           //r指向p后面的那个节点
p->pNext = r->pNext;
free(p->->pNext);


  插入节点:

   将新的节点q插入链表中p的后边:



r = p->pNext;  p->pNext = q;   q->pNext = r ;
或:q->pNext = p->pNext; p->pNext = q;


  算法:

   狭义的算法与数据存储方式密切相关

   广义的算法与数据存储方式无关

   泛型:

    利用某种技术达到的效果就是:不同的存储方式,执行的操作时一样的。

   学算法,最重要的不是自己编算法,重要的是看懂已有的算法。重要的是看懂答案。

3、线性结构的两种常见结构一:栈

 定义

  一种可以实现“先进后出”的存储结构

  栈类似于箱子,

 分类

  静态栈

  动态栈(用的较多)

 算法

  出栈

  压栈

  每次压栈都压入栈顶

 应用

  函数调用

  中断

  表达式求职

  内存分配

  缓冲处理

  迷宫

4、线性结构的两种常见结构二:队列

5、专题:递归

 1)1+2+3+4….100的和(递归与循环的转换)

 2)求阶乘

 3)汉诺塔

 4)走迷宫

6、相关代码:

 1//链表操作代码

 2//数据存储位置相关代码

 3//栈操作相关代码

//链表操作代码
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

struct Node
{
int data;               //数据与
struct Node *pNext;     //指针域
}NODE ,*PNODE;      //NODE 等价于struct Node  PNODE等价于struct Node*

//函数声明
PNODE create_list(void);            //创建链表
void traverse_list(PNODE pHead);    //遍历链表
bool is_empty(PNODE pHead);         //判断链表为空
int length_list(PNODE);             //判断链表长度
bool insert_list(PNODE,int,int);    //插入
//在pHead所指向链表的第pos个节点的前面插入一个新的节点,该节点的值是val,并且pos的值从1开始。
bool delete_list(PNODE,int,int *);  //删除
void sort_list(PNODE);              //排序

int main(void)
{
PNODE pHead = NULL;     //等价于struct Node* pHead = NULL;

pHead = create_list()       //创建一个非循环单链表,并将该链表的头结点的地址赋给pHead
traverse_list(pHead);       //遍历链表

//输出链表长度
int len = length_list(pHead);
printf("链表长度是%d",len);

//判断链表是否为空
if(is_empty(PNODE))
printf("链表为空");
else
printf("链表不为空");

sort_list(pHead);           //排序
traverse_list(pHead);       //遍历链表

return 0;
}

PNODE create_list(void)
{
int len,i,val;

//分配了一个不存放有效数据的头节点
PNODE pHead =  (PNODE)malloc(sizeof(NODE));
if(NULL == pHead)
{
printf("分配失败");
exit(-1);
}

//定义一个指向尾节点的指针
PNODE pTail = pHead;
pTail->pNext = NULL;

printf("输入要生成链表节点的个数 : len = ");
scanf("%d",%len);

for(i=0;i<len;i++)
{
printf("请输入第%d个节点的值:",i+1);
scanf("%d",&val);

PNODE pNew = (PNODE)malloc(sizeof(NODE));
if(NULL == pNew)
{
printf("分配失败");
exit(-1);
}
pNew->data = val;
pTail->pNext = pNew;
pNew->pNext = NULL;
pTail = pNew;
}
return pHead;
}

void traverse_list(PNODE pHead)
{
PNODE p = pHead->pNext;

while(NULL!=p)
{
printf("%d ",p->data);
p = p->pNext;
}
printf("\n");

return;
}

bool is_empty(PNODE pHead)
{
if(NULL == pHead->pNext)
return true;
else
return false;
}

int length_list(PNODE pHead)
{
PNODE p = pHead->pNext;
int cnt;

while(NULL!=p)
{
cnt ++;
p= p->pNext;
}
return cnt;
}

void sort_list(PNODE pHead)
{
int i, j, t;
PNODE p,q;

int len = length_list(pHead);

for(i=0,p = pHead->pNext;i<len-1;++i,p = p->pNext)
{
for(j=i+1,q = p->pNext;j<len;++j,q = q->pNext)
{
if(p->data > q->pNext)
{
t = p->data;        //类似于t=a[i];
p->data = q->data;  //类似于a[i]=a[j];
q->data = t;        //类似于a[j]=t;
}
}
}

}

//在pHead所指向链表的第pos个节点的前面插入一个新的节点,该节点的值是val,并且pos的值从1开始。
bool insert_list(PNODE pHead,int pos,int val)       //插入
{
int i=0;
PNODE p = pHead;

while(NULL !=p && i<pos-1)
{
p=p->pNext;
++i;
}//指针p指向第pos个或最后一个节点。

if(i>pos-1 || NULL = p)//pos小于1或pos大于链表长度
return false;

PNODE pNew = (PNODE)malloc(sizeof(NODE));
if(NULL== pNew)
{
printf("动态分配内存失败!");
exit(-1);
}
pNew->data = val;

//  pNew插入链表中
PNODE q = p->pNext;
p->pNext = pNew;
pNew->pNext = q;

retuen true;
}

bool delete_list(PNODE pHead,int pos,int *pVal) //删除
{
int i=0;
PNODE p = pHead;

while(NULL !=p->pNext&& i<pos-1)
{
p=p->pNext;
++i;
}//指针p指向第pos-1个或最后一个节点。

if(i>pos-1 || NULL = p->pNext)//pos小于1或pos大于链表长度
return false;

PNODE q = p->pNext;
*pVal = q->data;

//删除p节点后边的节点
p->pNext = p->pNext->pNext;
free(q);
q = NULL;

retuen true;
}


//数据存储位置相关代码

#include<stdio.h>
#include<malloc.h>

void f(int k)
{
int m;
double *q = (doble *)malloc(200);
}

int main(void)
{
int i = 10;
int *p = (int *)malloc(100);

return 0;
}
//代码中 i、p、m、q,在栈里分配
//malloc开辟的100个,200个内存在堆里分配

//栈里的内存程序自动分配,动态内存需要程序员手动分配


//栈操作相关代码
/*
创建
压栈
出栈
遍历
清空
*/

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

typedef struct Node
{
intdata;
struct Node *pNext;
}NODE, * PNODE;

struct Stack
{
PNODE pTop;     //指向栈顶
PNODE pBottom;  //指向栈底
}STACK,* PSTACK;

void init(PSTACK);
void push(PSTACK pS,int val);
void traverse(PSTACK);
bool pop(PSTACK,int *);             //出栈
void clear(PSTACK pS);       //框架还在,里边的元素都没了

int main(void)
{
STACK S;
int val;

init(&S);                   //  初始化
push(&S,1);                 //压栈,不能指定位置,只能压栈到栈底
push(&S,2);                 //压栈
traverse(&S);               //遍历输出

clear(&S);                  //清空
traverse(&S);               //遍历输出

if(pop(&S,&val))                //出栈
{
printf("出栈成功,出栈元素是%d\n",val);
}
else
{
printf("出栈失败");
}

return 0;
}

void init(PSTACK pS)
{
pS->pTop = (PNODE)malloc(sizeof(NODE)); //栈顶,头结点(无数据节点)
if(NULL == pS->pTop)
{
printf("分配失败");
}
else
{
pS->pBottom = pS->pTop;
pS->pTop->pNext = NULL;     //pS->Bottom->pNext = NULL
}
}
void push(PSTACK pS,int val)
{
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = pS->pTop;         //新节点插入到原栈顶上方
pS->pTop = pNew;                //新节点成为栈顶

return;
}

void traverse(PSTACK pS)
{
PNODE p = pS->pTop;

while(p != pS->pBottom)
{
printf("%d  ",p->data);
p=p->pNext;
}
printf("\n");
retrun ;
}

bool empty(PSTACK pS)
{
if(pS->pTop == pS->pBottom)
return true;
else
return false;
}

//把pS所指向的栈出栈一次,并把出战的元素存入pVal形参所指向的变量中,
bool pop(PSTACK pS,int *pval)               //出栈
{
if(empty(pS))
{
return false;
}
else
{
PNODE r = pS->pTop;
*pval = r->data;
pS->pTop = r->pNext;
free(r);
r = NULL;

return true;
}
}

void clear(PSTACK pS)       //框架还在,里边的元素都没了
{
if(empty(pS))
{
return ;
}
else
{
PNODE p = pS->pTop;
PNODE q = p->pNext;

while(p!=pS->pBottom)
{
q=p->pNext;
free(p);
p = q;
}
pS->pTop = pS->pTop;
}

/*自己写的代码
PNODE r;

while(NULL != pS->pTop )
{
r = pS->pTop;
pS->pTop = r->pNext;
free(r);
}
*/
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构