您的位置:首页 > 其它

单链表以及静态链表的实现

2015-07-17 09:42 337 查看
注意:

我认为对于数据结构的深入理解并不是掌握书本上的概念,最重要的是自己的动手编写过程,其中有不少饶人的注意点,望读者有了基本了解之后,动手能够亲自实现,这是一个不一样的过程

**链表中的数据是以节点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。

· 以“结点的序列”表示线性表称作线性链表(单链表)

· 单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。

· 因此,查找第 i 个数据元素的基本操作为:移动指针,比较 j 和 i

单链表

1、链接存储方法

链接方式存储的线性表简称为链表(Linked List)。

链表的具体存储表示为:

① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)

② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))

注意:

链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。

2、链表的结点结构

┌───┬───┐

│data │next │

└───┴───┘

data域–存放结点值的数据域

next域–存放结点的直接后继的地址(位置)的指针域(链域)

注意:

①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。

②每个结点只有一个链域的链表称为单链表(Single Linked List)。

【例】线性表(bat,cat,eat,fat,hat,jat,lat,mat)的单链表示如示意图

3、头指针head和终端结点指针域的表示

单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。

注意:

链表由头指针唯一确定,单链表可以用头指针的名字来命名。

终端结点无后继,故终端结点的指针域为空,即NULL。

4、单链表注意点

①LinkList和ListNode是不同名字的同一个指针类型(命名的不同是为了概念上更明确)

②*LinkList类型的指针变量head表示它是单链表的头指针

③ListNode类型的指针变量p表示它是指向某一结点的指针

5、编写过程应了解的函数

①生成结点变量的标准函数

p=( ListNode *)malloc(sizeof(ListNode));

//函数malloc分配一个类型为ListNode的结点变量的空间,并将其首地址放入指针变量p中

②释放结点变量空间的标准函数

free(p);//释放p所指的结点变量空间

③结点分量的访问

利用结点变量的名字*p访问结点分量

方法一:(*p).data和(*p).next

方法二:p-﹥data和p-﹥next

④指针变量p和结点变量*p的关系

指针变量p的值——结点地址

结点变量*p的值——结点内容

(*p).data的值——p指针所指结点的data域的值

(*p).next的值——*p后继结点的地址

*((*p).next)——*p后继结点

注意:

① 若指针变量p的值为空(NULL),则它不指向任何结点。此时,若通过*p来访问结点就意味着访问一个不存在的变量,从而引起程序的错误。

② 有关指针类型的意义和说明方式的详细解释

可见,在链表中插入结点只需要修改指针。但同时,若要在第 i 个结点之前插入元素,修改的是第 i-1 个结点的指针。

因此,在单链表中第 i 个结点之前进行插入的基本操作为:

找到线性表中第i-1个结点,然后修改其指向后继的指针

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define Error 0
#define Ok 1
typedef int  ElemType;
typedef int  Status;
typedef struct Node
{
ElemType  data;
struct Node *next;

}Node,*LinkList;

typedef struct Node* LinkList;

/**
*  获得单链表的元素
*/
Status GetElem_L(LinkList L, int i, ElemType *e)
{
//工作指针后移;
int j = 1;
LinkList p ;

p = L->next;

while (p && j < i) {
p = p->next;
++j;
}

if (!p || j > i) {
return Error;
}

*e = p->data;
return Ok;

}

/**
*  单链表的插入
*/
LinkList ListInsert(LinkList *L, int i, ElemType e)
{
int j = 1;
LinkList p,s;

p = *L;

while (p && j < i) {
p = p->next;
++j;
}

if (!p || j > i) {
return Error;
}
s = (LinkList)malloc(sizeof(Node));

s->data = e;

s->next = p->next;
p->next = s;

return *L;
}

/**
*  单链表的删除
*/
LinkList ListDelete(LinkList *L, int i)
{
int j = 1;
LinkList p;

p = *L;

while (p && j < i) {
p = p->next;
++j;
}

if (!p || j > i) {
return Error;
}

p->next = p->next->next;

//    e = p->data;

free(p->next);
return *L;

}

/**
*  单链表的整表创建
动态生成
(头插法)始终让新节点插在第一的位置
*/
LinkList CreatList_LH(LinkList L,int n)
{
LinkList p;
int i ;

L = (LinkList)malloc(sizeof(Node));
L->next = NULL;

srand((unsigned)time(0));

for (i = 0; i < n; i++) {
p  = (LinkList)malloc(sizeof(Node));
p->data = rand()%100 + 1;
//printf("%d ",p->data);
p->next = L->next;
L->next = p;

}

return L;

}

/**
*  尾插法
*/
LinkList CreatList_LD(LinkList *L,int n)
{
LinkList p,r;
int i ;

srand((unsigned)time(0));

*L = (LinkList)malloc(sizeof(Node));
//L->next = NULL;
r = *L;

for (i = 0; i < n; i ++) {
p = (LinkList)malloc(sizeof(Node));
p->data = rand()%100 + 1;
//printf("%d ",p->data);
r->next = p;
r = p;
}

r->next = NULL;

return *L;
}

/**
*  单链表的清除
*/
Status ClearList(LinkList L)
{
LinkList q,p;

p = L->next;

while (p) {
q = p->next;
free(p);
p = q;
}

L->next = NULL;
return Ok;

}

Status LengthOfList(LinkList L)
{
int length;

while (L->next != NULL) {
length++;
L = L->next;

}
return length;
}

ElemType GetMidNode(LinkList *L)
{
LinkList search,mid;

mid = search = *L;
while (search->next != NULL) {

if (search->next->next != NULL) {

search = search->next->next;
mid = mid->next;
}
else
{
search = search->next;
mid = mid->next;
}
}

return mid->data;
}

int main()
{

LinkList list,start;

/*  printf("请输入单链表的数据:");
list = LinkedListCreatH();
for(start = list->next; start != NULL; start = start->next)
printf("%d ",start->data);
printf("/n");
*/  printf("请输入单链表的个数:");
int j = 0;
scanf("%d",&j);

list = CreatList_LD(&list, j);
for(start = list->next; start != NULL; start = start->next)
printf("%d ",start->data);

printf("\n");

int length = LengthOfList(list);
printf("%d",length);

printf("\n");
int i;
ElemType x;

printf("请输入插入数据的位置:");
scanf("%d",&i);

while (i > j||i <= 0) {
printf("请输入插入数据的位置:");
scanf("%d",&i);
}
printf("请输入插入数据的值:");
scanf("%d",&x);
list = ListInsert(&list, i, x);
for(start = list->next; start != NULL; start = start->next)
printf("%d ",start->data);

printf("\n");
ElemType k;
k =  GetMidNode(&list);
printf("%d",k);

printf("\n");
printf("请输入删除数据的位置:");
scanf("%d",&i);
list = ListDelete(&list, i);
for(start = list->next; start != NULL; start = start->next)
{   printf("%d ",start->data);}
printf("\n");

ClearList(list);

return 0;
}


**用数组描述的链表,即称为静态链表。

· 在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标cur。

· 这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define MaxSize 100
typedef int  ElemType;
typedef struct {
ElemType data;
int cur;

}SList,StaticLinkList[MaxSize];

/**
*  初始化
*/
void init_sl(StaticLinkList space)
{
int i;
for (i = 0; i < MaxSize - 1; i++) {
space[i].cur = i +1;
}

space[MaxSize-1].cur = 0;
}

/**
*  分配空闲结点
*/

int malloc_sl(StaticLinkList space)
{
int i = space[0].cur;
if (i) {
space[0].cur = space[i].cur;
}
return i;
}

int GetListLength(StaticLinkList space)
{
int j = 0;
int k = space[MaxSize - 1].cur;
while (k) {
j++;
k = space[k].cur;
}
return j;
}

void ListInsert(StaticLinkList L, int i, ElemType e)
{

int k = MaxSize - 1;

if (i < 1|| i > GetListLength(L) + 1) {
return;
}

int v = malloc_sl(L);
{

for (int j= 0 ; j < i- 1; j++) {
k = L[k].cur;//插入的前一个结点
}
L[v].data = e;
L[v].cur = L[k].cur;
L[k].cur = v;
}
}

void Free_SLL(StaticLinkList L,int j)
{
L[j].cur = L[0].cur;
L[0].cur = j;
}
/**
*  删除i位置的元素
*/
void DeleteList(StaticLinkList L, int i)
{
int k = MaxSize - 1;

if (i < 1|| i > GetListLength(L) + 1) {
return;
}

for (int j = 0; j < i -1; j++) {
k = L[k].cur;
}

int  temp = L[k].cur;
L[k].cur = L[temp].cur;
Free_SLL(L, temp);
}

void Print(StaticLinkList L) //打印链表
{
int k = L[MaxSize - 1].cur;
while(k)
{
printf("%d ",L[k].data);
k = L[k].cur;
}
printf("\n");
}

int main(int argc, const char * argv[]) {

srand((unsigned)time(0));

StaticLinkList L;
init_sl(L); //初始化链表
for(int i = 0;i < 8;++i)
ListInsert(L, i, rand()%100 + 1);
Print(L); //输出链表

int i,j;
printf("请输入插入的位置:");
scanf("%d",&j);
printf("请输入插入的值:");
scanf("%d",&i);
ListInsert(L,j,i); //在链表的第3个位置插入22
Print(L);

printf("请输入删除的位置:");
scanf("%d",&j);
DeleteList(L,j);
Print(L);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: