数据结构

来源:互联网 发布:360.cn 域名价格 编辑:程序博客网 时间:2024/05/01 17:02

-----------------------------------------------第一次作业--------------------------------------------------------------------------

1:什么是链表

动态分配存储结构,不会造成空间的浪费。链表有一个人头指针,通过头指针访问链表中其他的元素,除头指针外,剩余的为结点,每一个节点中有数据成员还有下一个节点元素的地址,通过地址访问下一个节点,所以,链表不像线性表一样是顺序存储结构。

2:链表的增删改查

#include<ctype.h>
#include<malloc.h> 
#include<stdio.h> 
#include<stdlib.h>
#include<process.h> 
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status; 
typedef int ElemType;
/*结构体的定义 */
struct LNode
{
ElemType data;
struct LNode *next;
};
typedef struct LNode *LinkList; 
/*创建一个新的链表*/
void InitList(LinkList *L)

*L = (LinkList)malloc(sizeof(struct LNode)); 
if (!*L) 
exit(OVERFLOW);
(*L)->next = NULL; 
}
/*链表的销毁*/
void DestroyList(LinkList *L)

LinkList q;
while (*L)
{
q = (*L)->next;
free(*L);
*L = q;
}
}
/*链表的增加操作*/
Status ListInsert(LinkList L, int i, ElemType e) 

int j = 0;
LinkList p = L, s;
while (p&&j<i - 1) 
{
p = p->next;
j++;
}
if (!p || j>i - 1)
s = (LinkList)malloc(sizeof(struct LNode));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
/*链表的删除操作*/
Status ListDelete(LinkList L, int i, ElemType *e) 

int j = 0;
LinkList p = L, q;
while (p->next&&j<i - 1) 
{
p = p->next;
j++;
}
if (!p->next || j>i - 1) 
return ERROR;
q = p->next; 
p->next = q->next;
*e = q->data;
free(q);
return OK;
}
/*链表的改变*/
Status ListChange(LinkList L, int i, ElemType *e)
{
int j = 0;
LinkList p = L->next;
while (p&&j <i - 1)
{
p = p->next;
j++;
}
if (!p || j > i - 1)
return ERROR;
p->data = *e;
return OK;
}
/*链表的访问*/
void ListTraverse(LinkList L)
{
LinkList p = L->next;
while (p)
{
printf("%3d", p->data);
p = p->next;
}
printf("\n");
}
/*主函数*/
void main()
{
LinkList L;
ElemType e;
Status i;
int j;
int num;
InitList(&L);
for (j = 1; j <= 5; j++)
i = ListInsert(L, 1, j);
printf("在L的表头依次插入1~5后:L=");
ListTraverse(L); 
printf("输入要改变元素的值:");
scanf_s("%d",&num);
i = ListChange(L,2,&num);
printf("改变链表元素以后的链表\n");
ListTraverse(L);
i = ListDelete(L, 4, &e); 
if (i == ERROR)
printf("删除元素失败\n");
else
printf("删除元素成功,其值为:%d\n", e);
        printf("依次输出删除后L的元素:");
ListTraverse(L);
DestroyList(&L);
}

链表中的数据结构如何分配内存单元

程序的内存可以划分为堆区,栈区,静态区,代码区。栈区编译器自动分配释放,存放函数参数,局部变量等。堆区是动态分配,由程序员完成。静态区存放全局变量和静态变量,程序结束后系统释放。代码区存放程序代码。数据结构中的链表是动态分配,需要用malloc申请内存,用delete释放内存。

树和二叉树

1:树的定义:树是n(n≥0)个结点的有限集合。若n=0,则称为空树;否则,有且仅有一个特定的结点被称为根,当n>1时,其余结点被分成m(m>0)个互不相交的子集T1,T2,...,Tm,每个子集又是一棵树。由此可以看出,树的定义是递归。

二叉树的定义:每个结点至多只有两棵子树(即不存在大于2的结点),且二叉树的子树有左右之分,其次序不能任意颠倒。

2:有几种树:有向树,二叉树

3:树的应用:树与二叉树的转换的实现、树的前序、后序的递归

4:简单的二叉树排序树:

----------------------------------------------------------------------------第二次作业-----------------------------------------------------------------------------------------------
a. 看懂代码单向链表、单向循环链表、双向链表、双向循环链表过程。 
b. 实现写以上链表,包括 增 删 改  查。(非常重要,关乎到你们大二的课程,很多人都不适应这个) 
(1)双向链表的增删改查:
#include<stdio.h>
#include<malloc.h>
#include<process.h>
#include<stdlib.h>
#include<ctype.h>
#define OK 1
#define ERROR 0
#define FALSE 0
#define TRUE 1
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;
/*双向链表中结构体的定义*/
typedef struct DuLNode {
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
}NuLNode,*DuLinkList;
/*建立空的双向链表*/
void InitList(DuLinkList *L)
{
(*L) = (DuLinkList)malloc(sizeof(struct DuLNode));
if (!*L)
exit(OVERFLOW);
(*L)->next = NULL;
}
/*链表的增加操作*/
Status ListInsert(DuLinkList L, int i, ElemType e)
{
int j = 0;
DuLinkList q,p=L;
q = (DuLinkList)malloc(sizeof(struct DuLNode));
while (p&&j < i - 1)/*指向第i个元素*/
{
p = p->next;
j++;
}
q->data = e;
q->next = p->next;
p->next = q;
p->next->prior = q;
q->prior = p;
return OK;
}
/*链表的删除操作*/
Status ListDelect(DuLinkList L, int i, ElemType *e)
{
int j = 0;
DuLinkList q, p=L;

while (p->next&&j < i - 1)
{
p = p->next;
j++;
}
q = p->next;
p->next = q->next;
q->next->prior = p;
*e = p->data;
    free(q);
return OK;
}
Status ListChange(DuLinkList L, int i, ElemType *e)
{
int j = 0;
DuLinkList p = L->next;
while (p&&j <i - 1)
{
p = p->next;
j++;
}
if (!p || j > i - 1)
return ERROR;
p->data = *e;
return OK;
}
void Traverse(DuLinkList L)
{
DuLinkList p = L->next;
while (p)
{
printf("%d", p->data);
p = p->next;
}
printf("\n");
}
/*主函数*/
void main()
{
ElemType e;
int i,j,num;
DuLinkList L;
InitList(&L);
for (j = 0; j < 5; j++)
i = ListInsert(L, 1, j);
printf("输入插入元素以后的双向链表元素:");
Traverse(L);
printf("输入要改变元素的值:");
scanf_s("%d", &num);
i = ListChange(L, 2, &num);
printf("改变链表元素以后的链表\n");
Traverse(L);
i = ListDelect(L, 4, &e);
printf("输出删除元素以后的链表:");
Traverse(L);
}
(2)单向循环链表:
#include<ctype.h>
#include<malloc.h> 
#include<stdio.h> 
#include<stdlib.h>
#include<process.h> 
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;
/*结构体的定义 */
struct LNode
{
ElemType data;
struct LNode *next;
};
typedef struct LNode *LinkList;
/*创建一个新的链表*/
void InitList(LinkList *L)
{
*L = (LinkList)malloc(sizeof(struct LNode));
if (!*L)
exit(OVERFLOW);
(*L)->next = NULL;
}
/*链表的销毁*/
void DestroyList(LinkList *L)
{
LinkList q;
while (*L)
{
q = (*L)->next;
free(*L);
*L = q;
}
}
/*链表的增加操作*/
Status ListInsert(LinkList L, int i, ElemType e) 

int j = 0;
LinkList p = L, s;
while (p->next!=L&&j<i-1) 
{
p = p->next;
j++;
}
if (p->next==L || j>i - 1) 
return ERROR;
s = (LinkList)malloc(sizeof(struct LNode)); 
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
/*链表的删除操作*/
Status ListDelete(LinkList L, int i, ElemType *e)
{
int j = 0;
LinkList p = L, q;
while (p->next->next!=L&&j<i - 1)
{
p = p->next;
j++;
}
if (!p->next || j>i - 1)
return ERROR;
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return OK;
}
/*链表的改变*/
Status ListChange(LinkList L, int i, ElemType *e)
{
int j = 0;
LinkList p = L->next;
while (p->next!=L&&j <i - 1)
{
p = p->next;
j++;
}
if (p->next==L|| j > i - 1)
return ERROR;
p->data = *e;
return OK;




}
/*链表的访问*/
void ListTraverse(LinkList L)
{
LinkList p = L->next;
while (p->next!=L)
{
printf("%3d", p->data);
p = p->next;
}
printf("\n");
}
/*主函数*/
void main()
{
LinkList L;
ElemType e;
Status i;
int j;
int num;
InitList(&L);
for (j = 1; j <= 5; j++)
i = ListInsert(L, 1, j);
printf("在L的表头依次插入1~5后:L=");
ListTraverse(L);
printf("输入要改变元素的值:");
scanf_s("%d", &num);
i = ListChange(L, 2, &num);
printf("改变链表元素以后的链表\n");
ListTraverse(L);
i = ListDelete(L, 4, &e);
if (i == ERROR)
printf("删除元素失败\n");
else
printf("删除元素成功,其值为:%d\n", e);
printf("依次输出删除后L的元素:");
ListTraverse(L);
DestroyList(&L);
}
(3):双向循环链表:
#include<stdio.h>
#include<malloc.h>
#include<process.h>
#include<stdlib.h>
#include<ctype.h>
#define OK 1
#define ERROR 0
#define FALSE 0
#define TRUE 1
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;
/*双向链表中结构体的定义*/
typedef struct DuLNode {
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
}NuLNode, *DuLinkList;
/*建立空的双向链表*/
void InitList(DuLinkList *L)
{
(*L) = (DuLinkList)malloc(sizeof(struct DuLNode));
if (!*L)
exit(OVERFLOW);
(*L)->next = NULL;
}
/*链表的增加操作*/
Status ListInsert(DuLinkList L, int i, ElemType e)
{
int j = 0;
DuLinkList q, p = L;
q = (DuLinkList)malloc(sizeof(struct DuLNode));
while (p->next!=L&&j < i - 1)/*指向第i个元素*/
{
p = p->next;
j++;
}
q->data = e;
q->next = p->next;
p->next = q;
p->next->prior = q;
q->prior = p;
return OK;
}
/*链表的删除操作*/
Status ListDelect(DuLinkList L, int i, ElemType *e)
{
int j = 0;
DuLinkList q, p = L;


while (p->next->next!=L&&j < i - 1)
{
p = p->next;
j++;
}
q = p->next;
p->next = q->next;
q->next->prior = p;
*e = p->data;
free(q);
return OK;
}
Status ListChange(DuLinkList L, int i, ElemType *e)
{
int j = 0;
DuLinkList p = L->next;
while (p->next!=L&&j <i - 1)
{
p = p->next;
j++;
}
if (!p || j > i - 1)
return ERROR;
p->data = *e;
return OK;
}
void Traverse(DuLinkList L)
{
DuLinkList p = L->next;
while (p->next!=L)
{
printf("%d", p->data);
p = p->next;
}
printf("\n");
}
/*主函数*/
void main()
{
ElemType e;
int i, j, num;
DuLinkList L;
InitList(&L);
for (j = 0; j < 5; j++)
i = ListInsert(L, 1, j);
printf("输入插入元素以后的双向链表元素:");
Traverse(L);
printf("输入要改变元素的值:");
scanf_s("%d", &num);
i = ListChange(L, 2, &num);
printf("改变链表元素以后的链表\n");
Traverse(L);
i = ListDelect(L, 4, &e);
printf("输出删除元素以后的链表:");
Traverse(L);
}
理论上变为循环链表只要将循环结构中的条件变一下就行。不是P或P->NEXT非空,而是是否等于头节点。然而修改了一下,程序还是有点小问题。
c. 了解链表的数据结构是如何分配内存的(内存对齐问题) 
链表的数据结构如何分配同第一次作业
动态分配中的内存对齐问题(摘自知乎)
1:内存对齐不仅仅是效率的问题,而是内存不对齐在某些情况下程序根本无法正常运行。主要用于不同cpu进行编程,会遇到内存不对齐就直接程序奔溃的情况 。x86是一种内存可以随意分配无需对齐的特例cpu而已。
2:内存对齐为了:
aa: 部分CPU不支持非对齐访问
bb: 大部分总线以BURST为单位读内存,burst通常大于一个字节,不对齐访问会让访问速度变慢
cc:cache读入一般以cacheline为单位更新。不对齐会占有多余cacheline。一般来说,会用cacheline为单位对齐,这样其他问题也得到相应权衡 ,linux内核还会提供这样功能的宏。考虑到pollution,对其的技巧就更复杂了。
dd:便于管理
d. 继续完成编写简单的二叉排序树,并了解hash散列问题。 
Hash分散问题:
1:分散式杂凑表(英语:Distributed Hash Table,简称DHT)是分散式计算系统中的一类,用来将一个关键值(key)的集合分散到所有在分散式系统中的节点,并且可以有效地将讯息转送到唯一一个拥有查询者提供的关键值的节点(Peers)。这裡的节点类似杂凑表中的储存位置。分散式杂凑表通常是為了拥有极大节点数量的系统,而且在系统的节点常常会加入或离开(例如网路断线)而设计的。在一个结构性的延展网路(overlay network)中,参加的节点需要与系统中一小部份的节点沟通,这也需要使用分散式杂凑表。分散式杂凑表可以用以建立更复杂的服务,例如分散式档案系统、点对点技术档案分享系统、合作的网页快取、多点传输、任意点传输(anycast)、网域名称系统以及即时通讯等。
二叉树排序:还不会,以后更新。
e. 建议了解一下队列、栈、链表的区别和共同点。
队列:从队尾进入,从队首出来
栈:先进后出。最先进去的为栈底,最后进入的为栈首。栈不能任意删除元素,只能从栈顶依次往下删除元素
链表:链表的操作相对较为自由。可以随意访问,删除,修改任意元素
栈是链表中特殊的一种

0 0
原创粉丝点击