数据结构-王道-线性表

线性表-链表

  • 线性表的链式储存又称为链表,他是指通过一组任意的存储单元来存储线性表中的数据元素。

单链表

typedf struct LNode
{
	ElemType data;
	struct LNode *next;
}
  • 因为单链表的数据元素是离散的分布在储存空间当中的,所以单链表是非随机存取的存取结构,即不能直接找到表中某个特定的的结点。查找某个特定的结点的时候需要从表头开始遍历,依次查找。

    头结点和头指针的区别:不管带不带头结点,头指针始终指向链表的第一个结点,而头结点是带头结点链表中的第一个结点,结点内通常不储存信息。

引入头结点之后可以带来两个优点:

  1. 由于开始结点的位置被存放在头结点的指针域中,所以在链表的第一个位置上的操作和在表的其他位置上的操作一致,无需对第一个位置进行特殊的操作。
  2. 无论链表是否为空,其头指针是指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也就统一了。
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;

头插法建立单链表

#ifndef NULL
    #ifdef __cplusplus
        #define NULL    0
    #else  /* __cplusplus */
        #define NULL    ((void *)0)
    #endif  /* __cplusplus */
#endif  /* NULL */
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode, *LinkList;

LinkList CreateListHead(LinkList &L)
{
    LNode *s;
    int x;
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;
    scanf("%d",&x);
    while(x!=9999)
    {
        s=(LinkList)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        scanf("%d",&x);
    }
    return L;
}
int main()
{
    LinkList L;
    CreateListHead(L);
    printf("%d",L->next->data);

    return 0;
}

尾插法建立单链表

LinkList CreateListHead(LinkList &L)
{
    LNode *s;
    int x;
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;
    scanf("%d",&x);
    while(x!=9999)
    {
        s=(LNode*)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        scanf("%d",&x);
    }
    return L;
}

获取第i个元素的值

LinkList GetElem(LinkList L,int i)//
{
    int j=0;
    LinkList l=L;
    if(i==0)        // 要第0个就是头结点的地址了。
        return L;
    if(i<0)         // 不存在负结点 好吧。
        return NULL;
    while(l&&j<i)   // l 不为null
    {
        l=l->next;
        j++;
    }
    return l;
}

双链表

双链表的定义

typedef struct DNode
{
    int data;
    struct DNode *prior,*next;
}DNode,*DLinkList;

书上没有要求但是还是写一个 双链表的头插法吧。

DLinkList CreateDListHead(DLinkList &L)
{
    int x,count=0;
    DLinkList s;
    L = (DLinkList)malloc(sizeof(DNode));
    L->prior=L->next=NULL;
    scanf("%d",&x);
    while(x!=9999)
    {
        if(count==0)
        {
            s=(DLinkList)malloc(sizeof(DNode));
            s->data=x;
            s->prior=L;
            s->next=L->next;
            L->next=s;
            count++;
        }
        else
        {
            s=(DLinkList)malloc(sizeof(DNode));
            s->data=x;          //  头插法
            s->prior=L;         //  新加入的s的头指针 存放L(头结点)的地址
            s->next=L->next;    //  s的尾指针存放L的后继结点。
            L->next->prior=s;   //  L的后继结点的头指针存放s的地址
            L->next=s;          //  ..
        }
        scanf("%d",&x);
    }
    return L;
}
int main()
{
    DLinkList L;
    CreateDListHead(L);
    printf("%d\n",L->next->next->next->prior->data);
    return 0;
}

静态链表 提一下好吧。
静态链表以\(next=-1\)作为结束标志。静态链表的插入,删除没什么好说的。为什么有这个鬼东西是因为:在一些不支持指针的高级语言(如Basic)中,这是一种巧妙的设计方法。

#define MaxSize 50
typedef struct
{
    int data;
    int next;
}SLinkList[MaxSize];

顺序表和链表的比较

  1. 存取方式

    顺序表可以顺序存取,也可以随机存取,链表只能从表头顺序取元素。
    欢迎使用马克飞象

  2. 逻辑结构和物理结构
    采用顺序存储时,逻辑上相邻的元素,其对应的物理位置也相邻。而采用链式存储的时候,逻辑上相邻的元素在物理上并不一定相邻,其对应的逻辑关系是通过指针链接来表示的。
    一定要搞清楚存取方式 和 储存方式。

  3. 查找,删除,插入操作。
    对于按值查找来说,当顺序表在无序的情况下,两者的时间复杂度均为\(O(n)\);特别的当顺序表有序的时候可以采用折半查找的方式去查找\(O(\log_2n)\)
    对于按序号查找,顺序表支持随机访问,时间复杂度仅为\(O(1)\),而链表的平均时间复杂度为\(O(n)\)。顺序表的插入,删除操作,平均需要移动半个表长的元素。链表的插入删除操作,只需要修改相关结点的指针即可。因为链表带有指针域所以储存密度较低。

  4. 空间分配
    顺序表在静态储存的情形下,一旦储存空间装满就不能扩充了,如果再加入新元素将出现内存溢出,需要实现分配足够大的空间,但是提前分配的太大了到时候可能又用不上。这个时候就需要动态储存出手了,虽然其储存空间可以扩充,但需要移动大量的元素,导致其操作效率太低,而且如果内存中没有更大块的连续空间的话,这时候扩充可能导致失败。链式储存的结点空间只在需要的时候申请分配,只要内存有空间就可以分配,不像前面的必须要连续,这样灵活而高效。


@(P38T21)

时间复杂度\(O(n)\),一边扫描就得到了想要的结果,这种狗题目容易想的是两边扫描的答案,但是这样的话 最高分十分,下面的可以吃满分也就是十五分。

int Search_k(LinkList L,int k)
{
    LinkList l=L;// 存放倒数第k个的值。
    bool flag = false;// 表示暂时没有找到。
    int i=0;
    while(L->next)
    {
        L=L->next;
        i++;
        if(i==k||flag)
        {
            flag=true;
            l=l->next;
        }
    }
    if(flag)
    {
        printf("%d\n",l->data);
        return 1;
    }
    else
    {
        printf("%d\n",0);
        return 0;
    }
}

@(P38T22)

挺简单的以后这种题目尽量一次遍历就搞定。 时间复杂度\(O(1)\)

typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode, *LinkList;

int ListLen(LinkList L)// 传入L但不加 取地址符号,不改变L原来的内容。
{
    int len=0;
    while(L->next)
    {
        len++;
        L=L->next;
    }
    return len;
}
LinkList FindAddr(LinkList L,LinkList I)
{
    int lenL,lenI;
    lenI=ListLen(I);
    lenL=ListLen(L);
    if(lenI>lenL)
    {
        while(lenI-lenL)
        {
            lenI--;
            I=I->next;
        }
    }
    if(lenI<lenL)
    {
        while(lenL-lenI)
        {
            lenL--;
            L=L->next;
        }
    }// 因为是找从哪里开始共同的后缀,但是两个链表不一定等长,所以将长的前面的剪掉就行了。
    while(L->next!=NULL&&L->next!=I->next)
    {
        I=I->next;
        L=L->next;
    }
    return L->next;//这个时候的L->next等于I->next。
    
}

@(p58T23)

typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode, *LinkList;

void DeleSame(LinkList L,int n)
{

    if(L->next==NULL)
        printf("voidmei ¿ÕÁË£¿");
    LinkList l;
    l=L;
    int store[n+1];
    for(int i=0;i<=n;i++)
        store[i] = 0;
    while(l->next!=NULL)
    {
        int temp = l->next->data>0?l->next->data:-l->next->data;
        if(store[temp]==0)      // 如果这个数字(绝对值)没有出现过
        {
            store[temp]++;      // 标记一下出现
            l=l->next;          // 跳过该结点,检查下一个结点。
        }
        else                    // 出现过:让下一个结点的下一个结点作为当前结点的下一个结点。
            l->next=l->next->next; // 删除 该删除的结点。

    }
}
LinkList CreateListHead(LinkList &L)
{
    LNode *s;
    int x;
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;
    scanf("%d",&x);
    while(x!=9999)
    {
        s=(LNode*)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        scanf("%d",&x);
    }
    return L;
}
int main()
{
    LinkList L,i;
    CreateListHead(L);
    DeleSame(L,22);
    if(L->next==NULL)
        printf("¿ÕÁË\n");
    while(L->next!=NULL)
    {
        L=L->next;
        printf("--------%d-----------------\n",L->data);
    }
    free(L);
    return 0;
}
posted @ 2018-09-16 01:07  X-POWER  阅读(577)  评论(0编辑  收藏  举报