线性表专题2 - 2020-4-1- 算法 02

191 阅读3分钟

线性表-链表结构与顺序存储结构优缺点对比

空间性能

  • 顺序存储结构需要预先分配存储空间,分太大,浪费空间;分太小,发生上溢出;
  • 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制;

时间复杂度

查找
  • 顺序存储O(1)
  • 单链表O(n)
插入和删除
  • 顺序存储结构需要平均移动一个表长一半的元素 O(n)
  • 单链表O(1)

单向循环链表

4-1 主要学习了单向循环列表的增删改查

  • 链表的结点数据结构是一个存储数据的int类型data以及指向下一个结点的指针next
typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
//定义结点
typedef struct Node{
    ElemType data;
    struct Node *next;
}Node;

typedef struct Node * LinkList;

循环链表的创建与插入

2种情况

/*
    *L 就是初始指针
*/
status CreateList(LinkList *L) {
     //产生头结点,并使用L指向此头结点
    *L = (LinkList)malloc(sizeof(Node));
    //存储空间分配失败
    if(*L == NULL) return ERROR;
    //将头结点的指针域置空
    (*L)->next = NULL;
    
    return OK;
}

1 创建

  • YES 新节点;新节点next->自身
  • NO 链表结尾的位置;尾节点next->新节点; 新的节点next->首元结点

2 新增(插入)数据

1 插入位置在首元结点上

  • 判断插入位置是否在首元结点上
  • 创建新节点,并赋值给新节点

2 插入位置在其他位置

  • 不用判断是在中间插入还是在尾部插入,都是一样的

循环链表插入
Status ListInsert(LinkeList *L,int place,int num){
    LinkList temp,target;
    int i;
    if(place == 1){
        //1 创建temp 
        //2 链表中最后一个结点位置
        //3 新的结点next指向头结点
        //4 尾节点next指向新的头结点
        //5 让*L 指向temp

        temp = (LinkList)malloc(sizeof(Node));
        if(temp == NULL) return ERROR;
        temp->data = num;
        for(target = *L;target->next != *L;target = target->next);
        temp->next = *L;
        target->next = temp;
    
    }else{
        //1 创建temp temp就是插入的新节点
        //2 找到插入的前一个位置 target
        //3 新节点的next指向target-next
        //4 target->next = temp target就是插入位置的前一个结点
        temp = (LinkList)malloc(sizeof(Node));
        if(temp == NULL) return ERROR;
        temp->data = num;
        for(i=1,target = *L;target->next != *L && i!=place-1;target = target->next;i++); //避免循环多次遍历链表
        temp->next = target->next;
        target-next = temp;
        
    }
    return OK;
}

循环链表的删除

直接上代码

/*
L 指向链表的指针
place 删除的位置
*/
Status LinkListDelete(LinkList *L,int place){
    LinkList temp,target;
    int i;
    temp = *L;
    if(temp == NULL) return ERROR;
    if(place == 1){
        //如果删除的是首元结点
        //1 找到尾结点
        //2 新节点作为首结点
        for(target = *L;target->next != *L;target = target->next);
        *L = (*L)->next;
        target->next = *L;
        free(temp); //还要释放删除的结点
    }else{ //如果是其他结点
        //1 删除的位置
        //2 找到删除的前面的结点 target
        //3 创建temp指向target的下一个结点
        //4 释放temp
        for(i=1,target = *L;target->next != *L && i!=place-1;i++){
            target = target->next;
        }
        temp = target ->next;
        target->next = temp->next;
        free(temp);
    }
    return OK;
}

循环链表的查询

单向循环链表的查询

int findValue(LinkList L,int value){
    int i = 1;
    LinkList p;
    p = L;
    while(p->data != value && p->next != L){
        i++;
        p = p->next;
    }
    if(p->next == L && p->data !=value){
        return -1;
    }
    return i;
}

单链表查询倒数第k个节点方案 \color{red}{算法思想:定义两个指针p,q ,q先走k步,之后p,q同时移动 p所指向的即为所求}

int Search_k(LinkList L,int k){
 	if(L==NULL||L->next==NULL)
 		return 0;
 	int count=0;
	LinkList p,q;
	p=q=A->next;
	
	while(q){
		if(count<k){  
			count++;
		}else{
			p=p->next;
		}
		q=q->next;
	}  
	
 	if(count<k)  //当q=null的时候count还没有达到k说明k大于链表总长度 
 		return 0;
 	printf("%d\n",p->data);
 	return 1;

未完待续

双向链表

双向循环链表