3、数据结构与算法 - 单向循环链表

 大纲:

 单向循环链表

  1. 创建
  2. 循环遍历
  3. 插入
  4. 删除
  5. 查找

 
 循环链表

 一、单向循环链表

 循环链表中没有首结点,都是首元结点

 

#include <stdio.h>
#include "string.h"
#include "ctype.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"

#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1

#define MAXSIZE 20 //存储空间初始分配量

typedef int Status;//Status 是函数的类型,其值是函数结果状态代码l,如OK等
typedef int ElemType;//ElemType 类型根据实际情况而定,这里假设为int

//定义结点
typedef struct Node{
    ElemType data;
    struct Node *next;
}Node;

typedef struct Node * LinkList;

 

1、循环链表的初始化及赋值

有两种情况:1、第一次创建  2、已经创建
 (1)、第一次创建,只有一个L指针的时候,还没有任何结点
 (2)、已经有结点之后的插入
 
 

方法1

/*
 1、创建单向循环链表  方法1
 判断是否是第一次创建链表
 YES ->创建一个新结点,并使得新结点的next 指向自身; (*L)->next = (*L);
 NO ->找链表尾结点,将尾结点的next = 新结点。新结点的next = (*L)
 */
//LinkList *L 为什么要 带* 。当需要修改其本身的时候需要加 *,当不需要修改其本身的时候,例如打印就不需要*
//单链表找尾结点,是根据尾结点的next 为NUll(空)。单向循环链表的尾结点指向 L
Status CreateList(LinkList *L){
    
    int item;
    LinkList temp = NULL;
    LinkList target = NULL;
    printf("输入结点的值,输入0结束\n");
    while (1) {
        scanf("%d",&item);//用item 接收输入的数字
        if (item==0) break;//如果输入的是0 输入结束
        
        //如果输入的链表是空。则创建一个新的结点,使其next 指针指向自己 (*head)->next = *head;
        if (*L == NULL) {
            *L = (LinkList)malloc(sizeof(Node));//LinkList 是可以不加的,但是养成代码习惯还是要加上的
            if(!L) exit(0);//退出
            (*L)->data = item;//将输入的值存入结点
            (*L)->next = *L;//将结点指向自己
        }else{
            //输入的链表不是空的,寻找链表的尾结点,使尾结点的next=新结点。新结点的next指向头结点
            //1、找到最后一个结点
            //从tatget = *L 第一个位置开始遍历。
            //如果 tatget->next = *L 的时候就是尾结点了,所以 != *L 的话继续循环
            // != L 的时候将tatget赋值从下一个结点( tatget->next 指向下一个结点),继续遍历,直到 tatget->next = *L 的时候,这个时候的tatget就是尾结点
            for (target = *L; target->next != *L; target = target->next);
            //2、创建新结点
            temp = (LinkList)malloc(sizeof(Node));
            if (!temp) return ERROR;
            //3、向新创建的结点中存储数据
            temp->data = item;
            temp->next = *L;
            target->next = temp;//在尾结点后面插入新创建的结点
        }
    }
    return OK;
}

 方法2

/*
 2、创建单向循环链表  方法2
 方法1 是通过循环遍历的方式找到尾结点。我们也可以用一个指针一直指向尾结点,在插入数据的时候就方便找到尾结点
 */
Status CreateList2(LinkList *L){
    
    int item;
    LinkList temp = NULL;
    LinkList r = NULL;
    printf("输入结点的值,输入0结束\n");
    while (1) {
        scanf("%d",&item);//用item 接收输入的数字
        if (item==0) break;//如果输入的是0 输入结束
        
        //如果输入的链表是空。则创建一个新的结点,使其next 指针指向自己 (*head)->next = *head;
        if (*L == NULL) {
            *L = (LinkList)malloc(sizeof(Node));//LinkList 是可以不加的,但是养成代码习惯还是要加上的
            if(!L) exit(0);//退出
            (*L)->data = item;//将输入的值存入结点
            (*L)->next = *L;//将结点指向自己
            r = *L;// r 指向 *L
        }else{
            //输入的链表不是空的,r 指向尾结点,使尾结点的next=新结点。新结点的next指向头结点
            //2、创建新结点
            temp = (LinkList)malloc(sizeof(Node));
            if (!temp) return ERROR;
            //3、向新创建的结点中存储数据
            temp->data = item;
            temp->next = *L;
            r->next = temp;//在尾结点后面插入新创建的结点
            
            r = temp;//r 指向最新添加到链表中的结点,也就是最后一个结点
        }
    }
    return OK;
}

结果是一样的,所以就写一种的输出

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, World!\n");
    
    LinkList head;
    int place,num;
    int iStatus;
    
//    iStatus = CreateList(&head);//通过遍历查找尾结点
    iStatus = CreateList2(&head);//通过一个指针指向尾结点方便插入
    printf("原始的链表:\n");
    ListTraverse(head);

//******************************************************
输入结点的值,输入0结束
4
7
3
8
0
原始的链表:
    4    7    3    8

2、遍历链表

//2、遍历一下链表,循环链表的遍历最好用 do while 语句,因为头结点就有值
void ListTraverse(LinkList p)
{
    //如果链表是空
    if (p == NULL) {
        printf("打印的链表为空!\n");
        return;
    }else{
        LinkList temp;
        temp = p;//从第一个结点开始
        do {
            printf("%5d",temp->data);
            temp = temp->next;//下一个结点
        } while (temp != p);//如果等于p,循环完毕不再执行
        printf("\n");
    }
}

3、插入数据

 (1)、插入位置在首元结点上
        1)、判断插入位置是否在首元结点上
        2)、创建新结点,并复制给新结点
             插入过程:
             1、将新创建的结点 next 指向原来的首元结点
             2、将尾结点 next 指向新创建的结点
             3、将L指针指向新创建的结点
 

 (2)、其他位置插入
    例如: a b c d  在 b c中间插入e
       1)、创建新结点(target e),并复制给新结点
       2)、找到插入的位置的前一个结点(b)
            插入过程:
            1、找到插入结点前一个结点(b)
            2、将新创建结点的next 指向插入位置后面的结点(e->next = c)
            3、然后再把插入位置前面的结点next 指向新创建的结点(b->next= e)

//3、循环链表插入
Status ListInsert(LinkList *L, int place, int num){
    LinkList temp,target;//创建辅助变量
    int i;
    if (place == 1) {
//        如果插入的位置为1,则属于插入首元结点,所以需要特殊处理
//        1、创建新结点temp,并判断是否创建成功,成功则赋值,否则返回 ERROR;
//        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;
        *L = temp;
    }else{
//        如果插入的位置在其他位置
//        1、创建新结点temp,并判断是否创建成功,成功则赋值,否者返回 ERROR
//        2、先找到插入的位置,如果超过链表长度,则自动插入队尾;
//        3、通过target 找到要插入位的前一个结点,让target->next = temp;
//        4、插入结点的前驱指向新结点,新结点的next 指向target 原来的next 位置;
        temp = (LinkList)malloc(sizeof(Node));
        if (temp == NULL) return ERROR;
        
        temp->data = num;//新结点赋值
        
        //查找插入位置的前一个结点。如果超过链表长度插到最后
        //i=1, target = *L       从第一个节点开始遍历
        //target->next != *L     不是最后一个结点  && i != place-1  不是需要插入的位置请一个结点位置
        //target = target->next  target 赋值成下一个结点继续判断  同时 i++,正在查看的位置向后移动1位
        for (i=1,target = *L; target->next != *L && i != place-1; target = target->next, i++);
        
        temp->next = target->next;//新结点指向插入位置前一个结点所指向的结点 (E->next = B->next (C))
        target->next = temp;//插入位置前一个结点指向新创建的结点 (B->next = E)
        
    }
    return OK;
}
printf("请输入要插入的数据以及位置用空格隔开:");
scanf("%d %d",&place,&num);
iStatus = ListInsert(&head, place, num);
ListTraverse(head);

//*************************************************
原始的链表:
    4    7    3    8
请输入要插入的数据以及位置用空格隔开:2 99
    4   99    7    3    8
循环链表查询值:

4、删除

这里删除返回的是1 和 0 代表删除成功或失败,也可以将删除的值返回

//4、循环链表的删除
Status LinkListDelete(LinkList *L, int place){
    LinkList temp, target;
    int i;
//    temp指向首元结点
    temp = *L;
    if (temp == NULL || place < 1) return ERROR;
    
    //删除的是首元结点
    if (place == 1) {
        //1、如果删除的只剩下首元结点,则直接将 *L置空
        if ((*L)->next == (*L)) {
            (*L)->next = NULL;
            return OK;
        }
        
        //2、链表还有其他数据,删除首元结点的时候
        //(1)、找到尾结点,使尾结点next 指向头结点的下一个结点 target->next = (*L)->next;
        //(2)、新结点作为头结点,则释放原来的头结点
        for (target = *L; target->next != *L; target = target->next);
        temp = *L;
        
        *L= (*L)->next;
        target->next = *L;
        free(temp);
    }else{
        //如果删除其他结点
        //1、找到删除结点前一个结点target
        //2、使得target->next 指向下一个结点
        //3、释放需要删除的结点temp
        for (i=0,target = *L; target->next != *L && i != place-1; target = target->next, i++);
        
//        if (target->next == *L && i != 0) return ERROR;//超出链表长度的值的时候
        if (place > i) return ERROR;//
        
        temp = target->next;
        target->next = temp->next;
        free(temp);
    }
    return OK;
}
printf("循环链表删除值:");
scanf("%d",&place);
num = LinkListDelete(&head, place);
printf("\n删除(1 成功, 0 失败) %d\n",num);
ListTraverse(head);

//********************************************
    3   99    4    2
循环链表删除值:1

删除(1 成功, 0 失败) 1
   99    4    2

5、查询

//5、循环链表查询值 的位置
int findValue(LinkList L,int value){
    int i = 1;
    LinkList p;
    p = L;
    
//    寻找链表中的结点 data = value
//    循环 p->data 不是我们要找的,同时 还没有找到最后的时候 i++继续下一个
    while (p->data != value && p->next != L) {
        i++;
        p = p->next;
    }
    
//    遍历完之后,如果p 指针指向第一个结点,同时data != value  返回-1,也就是没找到。找到了就返回对应的位置
    if(p->next == L && p->data != value) return -1;
    
    return i;
}
printf("循环链表查询值:");
scanf("%d",&num);
place = findValue(head, num);
if (place == -1) {
    printf("链表中没有您所查询的值!\n");
}else
    printf("查询到值的位置:%d \n",place);
ListTraverse(head);
    
//*************************************
    3   99    4    2
循环链表查询值:4
查询到值的位置:3 
    3   99    4    2
发布了104 篇原创文章 · 获赞 13 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/shengdaVolleyball/article/details/105288188