TableOfContents

线性表Linear List

1. 线性表的定义

2. 线性表的逻辑结构特征

3. 例子

4. 常见的线性表的基本运算

对于实际问题中涉及的其它更为复杂的运算,可以用基本运算的组合来实现。

顺序表 Sequential List

1. 顺序表的定义

2. 顺序表图示

3. 顺序表的实现

   1 #define MAXSIZE 100
   2 typedef int elem_type;
   3 typedef struct{
   4     elem_type  elem[MAXSIZE];
   5     int size; //表示数组中元素个数
   6 }seq_list;

4. 初始化

   1 void init_list( seq_list * slt) {
   2     slt->size=0;
   3 }

5. 顺序表的遍历

void print_list (seq_list  *slt)
{
   int i;
   for( i=0; i < slt->size; i++) 
        printf("%5d", slt->elem[i]);
}

6. 判断顺序表是否为空

int empty_list ( seq_list  *slt ) {
     return  slt->size==0;
}

7. 查找顺序表中值为x的结点位置

int locate_list(seq_list *slt, ElemType x)
{
    int i=0;
    while(i < slt->size && slt->elem[i]!=x) 
        i++;
    return i<=slt->last? i+1:-1;
}

8. 取得顺序表中第i个结点的值

ElemType get_data(seq_list *slt, int position) {
    position--;
    if(position < 0 || position >= slt->size){
        ElemType x;
        printf("invalid position!");
        return x;
    } else
        return slt->elem[position];
}

9. 顺序表任意位置插入

void insert_list(seq_list *slt, int position, ElemType x) { 
    int i;
    position--;
    if(slt->size == MAXSIZE){ 
        printf("Full"); return;
    }
    if(position < 0 || position > slt->size) {
        printf("invalid position!"); return;
    }
    for(i = slt->size; i > position; i--) 
        slt->elem[i] = slt->elem[i-1];
    slt->elem[position]=x;
    slt->size++;
}

10. 插入算法时间性能分析

11. 删除顺序表中任意元素

void delete_list(seq_list *slt, int position) {
    int i;
    position--;
    if(slt->size==0) {
        printf("empty");return;
    }
    if(position<0 || position >= slt->size) {
        printf("invalid position!");return;
    }
    for(i=position; i<slt->size-1; i++) 
        slt->elem[i]=slt->elem[i+1];
    slt->size--;
}

12. 删除算法时间效率

13. 顺序表的用法举例

int main() {
    seq_list  sqlist;
    init_list(&sqlist);
    insert_list(&sqlist, 1, 1);
    print_list(&sqlist);
    printf("%d", locate_list(&sqlist, 10));
    printf("%d", locate_list(&sqlist, 11));
    while(!empty_list(&sqlist))
        delete_list(&sqlist, sqlist.size);
    print_list(&sqlist);
}

链表

1. 链式存储结构

数据结构的存储方式必须体现它的逻辑关系。在链式存储方式下,除存放一个结点的信息外,还需附设指针,用指针体现结点之间的逻辑关系。

如果一个结点有多个后继或多个前驱,那么可以附设相应个数的指针,一个结点附设的指针指向的是这个结点的某个前驱或后继。

2. 链表

线性结构的链式存储被称为链表。链表中可以只附设一个指针指向它的后继结点的存放位置;也可以设两个指针,一个指向前驱一个指向后继。

3. 单链表

单链表是线性表链式存储的一种形式。其中的结点一般含有两个域,一个是存放数据信息的域,另一个是存放该结点的后继结点的地址的指针域。一个单链表必须有一个首指针指向单链表中的第一个结点。

4. 带头节点的单链表

普通单链表的缺点:特殊情况太多,处理起来太麻烦

改进办法:增设头结点,头结点不存放任何数据

5. 数据结构实现

   1 typedef int ElemType;
   2 typedef struct Node{
   3    ElemType data;
   4    struct Node *next;
   5 }Node, *LinkList; 

6. 初始化

   1 void init_list(LinkList *L) {
   2    *L = (LinkList)malloc(sizeof(Node));
   3    (*L)->next = NULL;
   4 }

7. 插入算法

   1 void insert_list(Node *q, ElemType x) 
   2 {
   3    if(q==NULL) {
   4       return;
   5    }
   6    p = (Node*)malloc(sizeof(Node));
   7    p->data = x;
   8    p->next = q->next;
   9    q->next = p;
  10 }

8. 插入特定位置

   1 void insert_list_pos(LinkList node, int pos, ElemType x) 
   2 {
   3    while(pos > 1) {
   4         node = node->next;
   5         pos--;
   6    }
   7    /*node = get_data(node, pos-1);*/
   8    insert_list(node, x);
   9 }

9. 删除算法

   1 void delete_list(Node *pre) 
   2 {
   3    Node *p;
   4    if(pre==NULL || pre->next == NULL)
   5       return;
   6    p = pre->next;
   7    pre->next=p->next;
   8    free(p);
   9 }

10. 删除特定位置元素算法

   1 void delete_list_pos(Node *node, int pos) 
   2 {
   3    while(pos > 1) {
   4       node = node->next;
   5       pos--;
   6    }
   7    /*node=get_data(node, pos-1);*/
   8    delete_list(head);
   9 }

11. 删除特定值的元素算法

   1 void delete_list_x(Node *head, ElemType x) 
   2 {
   3    node *pre = head;
   4    while(pre->next!= NULL && 
   5       pre->next->data != x) 
   6    {
   7       pre=pre->next;
   8    }
   9    delete_list(pre);
  10 }

12. 查找算法

   1 Node *get_data(Node *head, int pos) 
   2 {
   3    while(pos > 0) {
   4       head = head->next;
   5       pos--;
   6    }
   7    return head;
   8 }

   1 Node *find_x(Node *head, ElemType x) 
   2 {
   3    head = head->next;
   4    while(head!=NULL && 
   5       head->data != x) 
   6    {
   7       head=head->next;
   8    }
   9    return head;
  10 }

13. 思考

如何实现:

不带头结点的单链表

不设开始的头结点,head指针直接指向第一个元素。

插入、删除操作比较繁琐

循环单链表

如果希望从表中的任意一个结点开始,都能访问到表中的所有其它结点,可以设置表中最后一个结点的指针域指向表中的第一个结点,这种链表称为循环单链表(或单循环链表)

1. 循环单链表与单链表的不同

2. 循环单链表插入

3. 循环单链表的删除

4. 只设尾指针的循环单链表

在循环单链表中,常常只设一个尾指针不设头指针。

5. 例子:合并两个循环单链表

练习

  1. 设计一个算法,求顺序表中值为x的元素的个数。
  2. 设计一个算法,将顺序表倒置。
  3. 已知一个顺序表中的各结点的值是从小到大有序的,设计一个算法,插入一个值为x的结点,使顺序表中的结点仍然是从小到大有序的。
ch3n2k.com | Copyright (c) 2004-2020 czk.