数据结构与算法:线性表(下)

一.静态链表

1.什么是静态链表:
a.静态链表:分配一整片连续的内存空间,各个结点集中安置。(类似于数组)
b.静态链表与单链表的区别为:静态链表不存储指向下一个结点的地址,而是存储数组下标(游标),由于链表数据元素存储在一整片连续空间,因此可以通过数组下标访问得到。
当结点为链表最后一个结点时,其游标的值设为-1,即表示后面没有其他结点了。

二.链表的插入与删除

1.静态链表的插入操作:
前提:
在动态链表中,结点的申请和释放分别借用C语言的malloc()和free()两个函数来实现;
静态链表中:
操作的是数组,不存在像动态链表的结点申请和释放的问题,所以我们需要自己的实现这两个函数,才可以做到插入和删除操作。

a.首先,先获得空闲为的下标:

在这里插入代码片:
int getCur(StaticLinkList tan)
{
	int i = tan[0].cur;
	if(tan[0].cur)
	{
   tan[0].cur = tan[i].cur;
    } 
	return i;
}

插入前:(先找到空闲的下标)
数据结构与算法:线性表(下)
插入后:(把找到的空闲下标赋值,再把需要插入的下标的游标修改到需要插入的值里)
数据结构与算法:线性表(下)
b.静态链表的插入:

在这里插入代码片:
int ListInsert(StaticLinkList tan,int i,ElemType e)//静态链表中第i个元素之前插入新的数据e
{
	int l,j,k;
 
	k = MAXSIZE -1;//数组最后一个元素的下标
	if(i < 1|| i > ListLength(L)+ 1)//ListLength为计算链表长度的函数
		return error;
 
	j = getCur(tan);
 
	if(j)
	{
		tan[j].data = e;
		for(l = 1;l <= i - 1;l++)
		{
			k = tan[k].cur;
		}
 
		tan[j].cur = tan[k].cur;
		tan[k].cur = j;
 
		return bingo;
	}
 
	return  error;
}

2.静态链表的删除操作:
删除变化前:
数据结构与算法:线性表(下)删除变化后:(虽然数据还在,但程序已经将它设置为-忽略)
数据结构与算法:线性表(下)
c.静态链表的删除:

在这里插入代码片:
void recycleNode(StaticLinkList tan,int i)//将下标为k的空闲结点回收到备用链表
{
	tan[i].cur = tan[0].cur ;
	tan[0].cur  = i;
}
int ListDelete(StaticLinkList tan,int i)//删除链表中第i个数据元素
{
	int j,k;
	if(i < 1 || i > ListLength(L))return error;
 
	k = MAXSIZE - 1;
 
	for(j = 1;j <= i -1;j++)
	{
		k = tan[k].cur;//得到删除元素前一个元素的下标
 
	}
	j = tan[k].cur;//将要删除元素的下标
	tan[k].cur = tan[j].cur;
 
	recycleNode(tan,j);
 
	return bingo;
}

总结下静态链表的优缺点:

优点:在插入和删除操作时,只需要修改游标,不需要移动元素,从而改进了在顺序存储结构中的插入和删除操作需要大量移动元素的缺点。

缺点:1)失去了顺序存储结构随机存取的特性。2)没有解决连续存储分配(数组)带来的表长难以确定的问题。

三.循环链表

单循环链表(Circular Linked List):是一种头尾相接的链表。其特点是最后一个结点的指针域指向链表的头节点,整个链表通过指针域链接成一个环。
由于单循环链表中没有NULL指针,因此在遍历链表时,循环终止条件不在像单链表那样判断指针是否为空,而是判断是否等于某一特定指针,因为单循环链表的很对基本操作与前面的单链表相同或相似

四.双向链表

如果从任意结点出发访问到链表中的所有结点,用循环链表就很合适了,但是如果需要经常访问某节点的直接前驱,虽然用单链表的存储,也能实现,但是查找前驱结点需要链表进行遍历,效率较低,这时我们采用双向链表。
双向链表:指的是构成链表的每个结点中设立的两个指针域:一个指向前驱的指针域,一个指向后继的指针域;这样就形成了两个不同方向的链。

这里写了一个双向的循环链表:
//基本程序,与前面的程序差不多
#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0;

typedef char ElemType;
typedef int Status;
typedef struct DualNode
{
    ElemType data;
    struct DualNode* prior;
    struct DualNode* next;
}DualNode, * DuLinkList;

Status InitList(DuLinkList* L)
{
    DualNode* p, * q;
    int i;

    *L = (DuLinkList)malloc(sizeof(DualNode));

    if (!(*L))
    {
        return ERROR;
    }

    (*L)->next = (*L)->prior = NULL;
    p = (*L);

    for (i = 0; i < 26; i++)
    {
        q = (DualNode*)malloc(sizeof(DualNode));
        if (!q)
        {
            return ERROR;
        }

        q->data = 'A' + i;
        q->prior = p;
        q->next = p->next;
        p->next = q;
        p = q;
    }

    p->next = (*L)->next;
    (*L)->next->prior = p;

    return OK;
}

void caser(DuLinkList* L, int i)
{
    if (i > 0)
    {
        do
        {
            (*L) = (*L)->next;
        } while (--i);

    }
    if (i < 0)
    {
        i = i - 1;
        (*L) = (*L)->next;

        do
        {
            (*L) = (*L)->prior;
        } while (++i);
    }

}

int main()
{
    DuLinkList L;
    int i, n;

    InitList(&L);
    printf("请输入一个整数:\n");
    scanf_s("%d", &n);
    printf("\n");

    caser(&L, n);

    for (i = 0; i < 26; i++)
    {
        L = L->next;
        printf("%c", L->data);
    }

    printf("\n");

    return 0;
}

上一篇:【Leetcode数据结构算法题】203. 移除链表元素(链表篇)


下一篇:Dotnet3.0下SnowFlake算法生成53位ID