线性表的链式存储与十三种运算操作

线性表的链式存储与运算实现

1 先修知识

1.1 malloc与new的区别

new会自动根据类型分配内存地址,并返回同类型的指针给引用

int *p1,*p2;
p1 = new int;
p2 = new int[100];

malloc只能动态分配内存,意思就是不会自动分配,必须人为设定内存大小与返回的指针类型

int *p;
p = (int*)malloc(sizeof(int)*100);

1.2 ->的用法

->是间接引用符,是二目访问符,类似于成员符 .

typedef struct Node{
    int a;
    double b;
}node, *linkList;
*linkList = &node;
//struct Node *p = &node;
//此时
linkList->a等价于(*linkList).a;

1.3 struct的用法

自定义类型struct

typedef struct Node{
    Elemtype a;
    Node *next;
}node,linkList; //结构变量node等有点像静态类,这里借用java编程思想描述,Node是父类,node,linkList是子类.
或
struct Node node,linkList;//按模板类型Node定义具体类型node,linkList

写一个struct Node,编译器只是读取它,并不会为它赋予内存空间.逻辑合理,它只是一个模板.

2 节点

节点由数据域和指针域构成.指针域决定先后链接顺序,有时链接关系不好修改的,可以直接交换数据域的内容,间接达到交换节点的目的.

单链表由一个个节点构成

typedef struct node{
    datatype data;
    struct node *next;
}LNode

node LNode = {};

等价于

public class node{
    Object data;
    class node next;
}
public class LNode extends node{}

3 栈

后进先出,前插法

抽象:表L; 新节点s(malloc,s->a=x); s->next=L(指向表头);L=s(表头指向s,s再指向next里保存的旧表头地址)

    linkList create_stack(int flag){
        linkList L = null; //linkList是指针子类,故L也是指针,又L=null静态声明,省去了malloc分配.
        // 同时! L==null;第一个节点s->next=L,巧妙地使最后一个节点的next为null.不会出现野指针.
        node *s;
        int x;
        scanf("%d",&x);
        int cout=1;
        while(cout<=flag){
            s=(Node*)malloc(sizeof(node));//每次循环都会手动new一个s.因为新的s节点的next后继是上一节点,所以新的s节点是上一节点的前驱.即新的s节点是前插的.满足栈后进先出的形式.
            s->data=x;
            s->next=L;//s上链指向L的表头,此时s还不算在L内
            L = s;//让s做L的表头,即巧妙地让L永远指向新的表头元素.
            scanf("%d",&x);
            cout++;
        }
        return L;
    }

4 队列

后进后出,尾插法

表L只要指向表头就够了,我们可以用副表指针*r先指向第一个节点(s作表头时),它与L都是指向第一个节点的引用.

linkList create_quene(int flag){
    linkList L=null;
    node *s,*r=null;
    int x;
    scanf("%d",&x);
    int cout=1;
    while(cout<=flag){
        s = malloc(sizeof(node)); //new一个s,new完对s的属性赋值
        s->a = x; 
        if(L=null) L=s;
        else r->next = s;上链
        r = s; //此处r,L都是s的软引用.L占了r的光,之后一条龙的链表全靠r接上.L最多指向表头,其余上链操作有r来完成
        scanf("%d",&x);
        cout++;
    }
    //定义表尾节点的后继节点为空.
}

5 利用表指针求表长

表指针顺节点往下走(赋值),表指针都是数据域为空,指针域指向当前节点,与节点同类型的内存空间.

后插法里的L,*r都是表指针,其中L作头指针变量,它所引用的节点叫头节点.即L是头节点,L->next才是第一个数据节点

int linkList_length(linkList L){
    node *p = L;
    int j=0;
    while(p->next!=nuLl){
        p=p->next;
        j++;
    }
    return j;
}

6 前插法与后插法

*p指向某个节点,*s指向待插入的新节点

graph LR
后插法
A(节点p)-->|起初令p->next=p',得到|B(p的下一节点是p')
A-->|最终p的下一节点是s|C
C-->|第二步p->next=s|A
C(待插入节点s)-->|第一步s->next=p`|B
graph BT
前插法
B(当前节点p)-->|第一步 q=L, while \q->next!=p\ q=q->next|A(找到p的前驱q)
C-->|第二步 s->next=p|B
A-->|第三步 q->next=s|C
C(待插入节点s)
graph TB
后插+交换实现前插
A(节点p)-->|起初 p->next=p`|B(p的下一节点是p`)
A-->|交换节点数据swap\p->next,s->next\|C
C-->|第二步p->next=s|A
C(待插入节点s)-->|第一步s->next=p`|B

7 删除节点

当前节点p,前驱节点q

  1. 已知p,找到它的前驱q
  2. *q->next = *p->next
  3. free§

8 删除当前节点的后一节点

当前节点*p

  1. node *s;
  2. s = p->next;
  3. p->next = s->next;
  4. free(s);

9 删除表L的第i个元素

  1. for循环找到L[i-1]
  2. 若L[i-1]->next != null
  3. 则用删除节点法,删除第i个节点

10 单循环列表

  1. 尾指针指向头指针
  2. 判断表已经遍历一遍的方法是p->next == head,是则已到尾指针.
  3. 有时可用r指向尾指针,直接从尾部开始遍历,加快运算.

11 单链表总结

单链表不具备按序号随机(直接)访问元素的能力,必须先找到它的前驱节点,才能访问要访问的节点.即只能从头指针开始访问.

12 双向链表

prior data next
typedef struct dlnode{
    datatype data;
    struct dlnode *prior,*next;
}DLnode,*DLinkList

单链表能做的事它都能做,最大的区别就是每修改一次链表,必须前后节点都要定义指向一次

12.1 插入

已知p,插入s
s->prior = p->prior;
p->prior->next = s;
p->prior = s;
s->next = p;

12.2 删除(free)

已知p,删除p

  1. p->prior->next = p->next;
  2. p->next->prior = p->prior;
  3. free§;

1.6 以a1为基准,划分线性表

划分就是重排列,比a1小的在前,大的在后

1.7 两线性表比较大小

A长a,B长b,两数组第一次不同时的下标i,A的剩余长度as,B的剩余长度bs,

  1. for循环使下标走到两数组第一次不同的地方,i
  2. for(j=i;j<a;j++){ AS[j-i]=A[j];a++;}
  3. for(j=i;j<b;j++){ BS[j-i]=B[j];b++;}
  4. if(asbs&&as0) return 0;//A==B
  5. if(as==0&&bs>0 || as>0&&bs>0&&AS[0]<BS[0]) return -1;//A<B
  6. else return 1;//A>B

1.8 倒转单链表

将原链表H中的每一个元素依次作为第一个元素插入到新链表中
void reverse(LinkList H){
Node *p;
p=H->next;
while§{
q=p;
p=p->next;
//插入q到头节点后面
q->next = H->next;
H->next = q;
}
}

删除表L中重复的元素

从首元素开始,遍历表L,删除与首元素相同的元素(修改链接关系),类推

两层遍历,两层while

void pur_LinkList(LinkList H){
    Node *p,*q,*r;
    p=H->next;
    while(p->next){
        q=p;
        while(q->next){
            if(q->next->data=p->next){
                r = q->next;
                q->next=r->next;
                free(r);
        }else{
            q=q->next;//下一个对比元素
        }
        p=p->next;//下一个首元素
    }
}

按访问权比排序链表元素

prior前驱指针域,data数据域,next后继指针域,freq权比域

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章