数据结构习题

第一章和第二章

GitHub:https://github.com/nothingsuibian/Simple-blog.git

一.顺序表

1.静态顺序表

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define Maxsize 5
typedef struct{
    int data[Maxsize];
    int length;
}sqlist;
void init_list(sqlist* lt){
    int i;
    for( i=0;i<Maxsize;i++){
        lt->data[i]=0;
    }
    lt->length=0;
}


void create_list(sqlist * lt, int num){
    printf("请输入元素:");
    int i;
    for( i =0; i<num;i++){
        scanf("%d",&lt->data[i]);
    }
    lt->length+=num;
}

void insert_list(sqlist * lt){
    int n,i,e; // n下标,i循环的,e 元素
    printf("请输入要插入的下标 和 元素:");
    scanf("%d %d",&n,&e);
    if(n>=0 && n<=lt->length){
        if(Maxsize==lt->length){
            printf("当前表满,插入失败!");
        }
        else{
            for(i=lt->length-1;i>=n;i--){
                lt->data[i+1] = lt->data[i];
            }
            lt->data[n] = e;

            lt->length++;
        }
    }
    else{
        printf("有效下标在0到%d之间:",lt->length);
    }
}

void delete_list(sqlist *lt)
{
    int n,i,s,m,j;
    s=0;
    printf("请输入要删除元素方式 1.下标 2.元素值:");
    scanf("%d",&n);
    if (n==1){
        printf("请输入要删除的元素下标:");
        scanf("%d",&m);

        if(n>=0 && m<= lt->length-1){
            printf("删除下标%d的元素值%d:\n:",m,lt->data[m]);
            for(i=m;i<lt->length-1;i++)
                {
                    lt->data[i]= lt->data[i+1];
                }
                lt->length--;
                s=1;

        }
        else{
            printf("表中下标0到%d:",lt->length-1);
        }

    }
    else if (n==2)
    {
        printf("请输入要删除的元素值:");
        scanf("%d",&m);
        for(i=lt->length-1;i>=0;i--)
            {
                if (lt->data[i]==m)
                    {
                        for(j=i;j<lt->length;j++)
                        {
                        lt->data[j]= lt->data[j+1];
                        }
                        lt->length--;
                        s=1;
                        break;
                    }

            }
        if(s==0){
            printf("无该元素");
        }


    }
    else{
        printf("输入错误");
    }

}

void print_list(sqlist lt){
    int i;
    if (lt.length!=0){
        printf("当前表中元素有:");
        for( i=0;i<lt.length;i++)
        {
            printf("%d\t",lt.data[i]);
        }
        printf(" 表长%d:\n",lt.length);
    }
    else{
        printf("当前为空表!");
    }

    printf("\n");

}

void find_list(sqlist lt){
    int n,i,m,s;
    s=0;
    printf("请输入要查找元素方式 1:下标 2:元素值:");
    scanf("%d",&n);
    if (n==1)
    {
        printf("请输入查找的元素下标:");
        scanf("%d",&m);
        if(m>=0 && m<= lt.length-1){
            printf("查找元素下标为%d的元素值为%d \n:",m,lt.data[m]);
            s=1;
        }
        else{
            printf("表中下标0到%d:",lt.length-1);
        }

    }
    else if (n==2)
    {
        printf("请输入要查找的元素值:");
        scanf("%d",&m);
        for(i=lt.length-1;i>=0;i--)
            {
                if (lt.data[i]==m)
                {
                    printf("元素下标为%d \n",i);
                    s=1;
                    break;
                }
            }

    }
    else
    {
        printf("输入错误");
    }
    if(s==0)
        {
        printf("未找到该元素,查找失败\n");
        }

}



int main(){
    int num;
    printf("输入创建表长:");
    scanf("%d",&num);
    sqlist lt;

    init_list(&lt);
    create_list(&lt,num);

    int n;

    while (1)
    {
        printf("输入要进行的操作:\n 1.查找 2.插入 3.删除: ");
            scanf("%d",&n);
            if (n==0){break;}
            switch(n)
            {
                case(1):
                    find_list(lt);
                    break;
                case(3):
                    delete_list(&lt);
                    break;
                case(2):
                    insert_list(&lt);
                    break;
                default:
                    printf("输入操作不存在!");
            }

        print_list(lt);
        printf("\n");
    }

}

2. 动态顺序表

#include <stdio.h>
#include <stdlib.h>

#include <stdbool.h>        //bool类型
# include <malloc.h>        //malloc  free函数


#define Maxsize 5

//动态顺序表
typedef struct{
    int *data;
    int max,length;
}sqlist2;

void init_list2(sqlist2* lt){
    if (lt !=NULL){
        lt->data =(int *)malloc(sizeof(int)*Maxsize); //申请空间
        lt->length=0;  //防止脏数据
        lt->max =Maxsize;
    }

}
void create_list2(sqlist2 * lt, int num){
    printf("请输入元素:");
    int i;
    for( i =0; i<num;i++){
        scanf("%d",&lt->data[i]);
    }
    lt->length+=num;
}
void extendplace(sqlist2 * lt){
    int n;
    printf("请输入要扩容的数目:");
    scanf("%d",&n);

//    int *p=lt->data; //辅助空间  方式一
      int *p; //辅助空间
      p=lt->data;

    lt->data =(int*)malloc((lt->max + n)*sizeof(int));
    int i;
    for(i=0;i<lt->length;i++){  //将原来顺序表数据复制到新空间
        lt->data[i]=p[i];
    }
    lt->max +=n;  //扩容n个
    free(p);
}

void insert_list2(sqlist2 * lt){
    int n,i,e; // n下标,i循环的,e 元素
    printf("请输入要插入的下标 和 元素:");
    scanf("%d %d",&n,&e);
    if(n>=0 && n<=lt->length){
        if(lt->max==lt->length){
            printf("当前表满,插入失败!");
        }
        else{
            for(i=lt->length-1;i>=n;i--){
                lt->data[i+1] = lt->data[i];
            }
            lt->data[n] = e;
            lt->length++;
        }
    }
    else{
        printf("有效下标在0到%d之间:",lt->length);
    }
}

void print_list2(sqlist2 lt){
    int i;
    if (lt.length!=0){
        printf("当前表中元素有:");
        for( i=0;i<lt.length;i++)
        {
            printf("%d\t",lt.data[i]);
        }
        printf(" 表长%d:\n",lt.length);
    }
    else{
        printf("当前为空表!");
    }

    printf("\n");

}


void find_list2(sqlist2 lt){
    int n,i,m,s;
    s=0;
    printf("请输入要查找元素方式 1:下标 2:元素值:");
    scanf("%d",&n);
    if (n==1)
    {
        printf("请输入查找的元素下标:");
        scanf("%d",&m);
        if(m>=0 && m<= lt.length-1){
            printf("查找元素下标为%d的元素值为%d \n:",m,lt.data[m]);
            s=1;
        }
        else{
            printf("表中下标0到%d:",lt.length-1);
        }

    }
    else if (n==2)
    {
        printf("请输入要查找的元素值:");
        scanf("%d",&m);
        for(i=lt.length-1;i>=0;i--)
            {
                if (lt.data[i]==m)
                {
                    printf("元素下标为%d \n",i);
                    s=1;
                    break;
                }
            }

    }
    else
    {
        printf("输入错误");
    }
    if(s==0)
        {
        printf("未找到该元素,查找失败\n");
        }

}

void delete_list2(sqlist2 *lt){
    int n,i,s,m,j;
    s=0;
    printf("请输入要删除元素方式 1.下标 2.元素值:");
    scanf("%d",&n);
    if (n==1){
        printf("请输入要删除的元素下标:");
        scanf("%d",&m);

        if(n>=0 && m<= lt->length-1){
            printf("删除下标%d的元素值%d:\n:",m,lt->data[m]);
            for(i=m;i<lt->length-1;i++)
                {
                    lt->data[i]= lt->data[i+1];
                }
                lt->length--;
                s=1;

        }
        else{
            printf("表中下标0到%d:",lt->length-1);
        }

    }
    else if (n==2)
    {
        printf("请输入要删除的元素值:");
        scanf("%d",&m);
        for(i=lt->length-1;i>=0;i--)
            {
                if (lt->data[i]==m)
                    {
                        for(j=i;j<lt->length;j++)
                        {
                        lt->data[j]= lt->data[j+1];
                        }
                        lt->length--;
                        s=1;
                        break;
                    }

            }
        if(s==0){
            printf("无该元素");
        }


    }
    else{
        printf("输入错误");
    }

}

void reback(sqlist2 * lt){
    lt->length=0;
}

void destory(sqlist2* lt){
    if(lt->data == NULL){
        printf("销毁失败!/n");
        return 0;
    }
    free(lt->data);
    free(lt);
    printf("销毁成功!/n");
}

int main(){
    int num;
    printf("输入创建表长:");
    scanf("%d",&num);
    int n;
    sqlist2 lt;  //申明一个动态顺序表
    init_list2(&lt);
    create_list2(&lt,num);
    while (1)
    {
        printf("输入要进行的操作:\n 1.查找 2.插入 3.删除: 4.扩容 5.表归零: 6.销毁表:");
            scanf("%d",&n);
            if (n==0){break;}
            switch(n)
            {
                case(1):
                    find_list2(lt);
                    break;
                case(3):
                    delete_list2(&lt);
                    break;
                case(2):
                    insert_list2(&lt);
                    break;
                case(4):
                    extendplace(&lt);
                    break;
                case(5):
                    reback(&lt);
                    break;
                case(6):
                    destory(&lt);
                    break;

                default:
                    printf("输入操作不存在!");
            }
        print_list2(lt);
        printf("\n");
    }


}

3.顺序表算法

1.(*与原题不一样)删除最小值并返回 后续元素全部进一

//1.删除最小值后续所有前移
bool delete_min(sqlist* lt,int *min){
    if(lt->length==0){
        printf("当前为空表!");
        return false;
    }
    int j=0;//初始化
    int e=lt->data[0];
    for(int i=1;i<lt->length;i++)
        {
            if (lt->data[i]<e)
                {
                    e=lt->data[i];
                    j=i;
                }
        }
    for(int i=j+1;i<lt->length;i++){
        lt->data[i-1]=lt->data[i];
    }
    lt->length--;
    *min =e;  //返回最小值
    return true;
}

2.逆置

void reverse_list(sqlist* lt){
    int start =0;
    int end = lt->length-1; //计算元素数量
//    int end = sizeof(lt->data) / sizeof(lt->data[0]);  // 计算元素数量方法二
    int e=0;
    while(start<end){
        e=lt->data[start];
        lt->data[start]=lt->data[end];
        lt->data[end]  =e ;
        start ++;
        end--;
    }

    for(start=0;start<lt->length;start++){
        printf("%d\t",lt->data[start]);
    }

}

3.删除所有值为num的元素

void num_delete(sqlist *lt,int e){
    int i,n=0;
    for (i=0;i<lt->length;i++){
        if(lt->data[i]!=e){
            lt->data[n]=lt->data[i];
            n++;
        }
    }
    lt->length=n;

    for(i=0;i<lt->length;i++){
        printf("%d\t",lt->data[i]);
    }
}

4.有序表删除 s-t之间的元素,s、t不合理返回false

//4.有序顺序表删除 a-b之间所有元素
bool range_delete(sqlist* lt,int start,int end){
    if ( start==end || start> end)
    {
        printf("删除不合法");//
        return false;
    }
    int i;
    for(i=0;i<lt->length;i++){
        if(lt->data[i]==start){
            start =i;
        }
        if(lt->data[i]==end){
            end=i;
        }
    }
    int newlength =end-start+1;
    for(i=end+1;i< lt->length;i++){
        lt->data[start++] = lt->data[i];
    }
    lt->length -=newlength;
    printf("%d\t%d删除后:",start,end);
    for(i=0;i<lt->length;i++){
        printf("%d\t",lt->data[i]);
    }
    return true;
}

5.无序删除s-t 之间元素

//5.无有序顺序表删除 a-b之间所有元素
bool no_sort_range_delete(sqlist*lt,int start,int end){
    if ( start==end || start> end)
    {
        printf("删除不合法");//
        return false;
    }
    int i;
    int num=0;  //记录不在范围内元素
    for(i=0;i<lt->length;i++){
        if(start>lt->data[i] || lt->data[i]>end)
        {
            lt->data[num]=lt->data[i];
            num++;
        }
    }
    lt->length=num;
    for(i=0;i<lt->length;i++){
        printf("%d\t",lt->data[i]);
    }
    return true;
}

6.有序表去重

//6.有序去重
bool Deduplicate(sqlist *lt){
    if(lt->length==0){
        return false;
    }
    int i=0;
    for(int j=1;j<lt->length;j++){
        if(lt->data[i]!=lt->data[j]){
            lt->data[++i]= lt->data[j];
        }
    }
    lt->length=i+1;
    for(int i=0;i<lt->length;i++){
        printf("%d\t",lt->data[i]);
    }
    return true;
}

7.合并有序表

//7.合并两个有序表
bool merge_list(sqlist *a,sqlist*b,sqlist* c){
    if(a->length==0 || b->length==0){
        return false;
    }
    int i=0,j=0,k=0;
    while(i< a->length && j< b->length){
        if(a->data[i] < b->data[j]){
            c->data[k++]=a->data[i++];
        }
        else{
            c->data[k++]=b->data[j++];
        }
    }
    while(i<a->length){
        c->data[k++]=a->data[i++];
    }
    while(j<b->length){
        c->data[k++]=b->data[j++];
    }
    c->length=k;  //更新c元素个数
    return true;
}

8.互换a、b顺序表

//8.互换a、b顺序表
void reverarray(int arr[],int start,int end){
    while(start<end){
        int temp = arr[start];
        arr[start++] =arr[end];
        arr[end--] =temp;
    }
}

void swapreverse(int arr[],int m,int n){
    reverarray(arr,0,m-1);
    reverarray(arr,m,m+n-1);
    reverarray(arr,0,m+n-1);
}
int main(){
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int m = 3; // Number of elements at the front
    int n = 7; // Number of elements at the back
    printf("Original Array: ");
    for (int i = 0; i < m+n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    if (m >= 0 && n >= 0) {
        swapreverse(arr, m, n);
        for (int i = 0; i < m+n; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    }
    return 0;
}

9(*参考代码插入未改变长度,添加 *lenggth)查找有序数组查找元素,找到与后继互换位置,未找到按顺序插入

// 9.查找序数组查找元素,找到与后继互换位置,未找到按大小顺序插入
void search_or_insert(int arr[],int* length,int e){
    int low=0, mid=0,end =*length-1; //长度
    while(low<=end){
        mid = (low+end)/2;
        if(arr[mid]==e){
           break;
        }
        else if(arr[mid]<e){
            low =mid+1;
        }
        else{
            end =mid-1;
        }
    }

    if(arr[mid]==e &&  mid!= *length-1 ){
    //如果查找成功换位,注意如果查找到最后一个因为没有后继则不操作
        int temp = arr[mid];
        arr[mid] = arr[mid+1];
        arr[mid+1] = temp;
    }
    if(low>end){
    //查找不成功插入,如果不用*length 主函数接收的length没变化会丢失一个数据
        for(int i=*length-1;i>end;i--){
            arr[i+1]=arr[i];
        }
        arr[end+1] = e;
       ( *length)++;
    }


}



int main(){
    int arr[] = {1,2,5,7,8};
    int length = sizeof(arr)/sizeof(arr[0]);
    for(int i=0;i<length;i++){
        printf("%d\t",arr[i]);
    }
    printf("\n");
    search_or_insert(arr,&length,5);
    for(int i=0;i<length;i++){
        printf("%d\t",arr[i]);
    }
    return 0;
}

10.一维数组左移p位

void reverarray(int arr[],int start,int end){
    while(start<end){
        int temp = arr[start];
        arr[start] =arr[end];
        arr[end] =temp;
        start++;end--;
    }

}
void test10(int arr[],int p,int length){
    reverarray(arr,0,p-1);
        printf("\n");
    for(int i=0;i<5;i++){
        printf("%d\t",arr[i]);
    }
    reverarray(arr,p,length-1);
        printf("\n");
    for(int i=0;i<5;i++){
        printf("%d\t",arr[i]);
    }
    reverarray(arr,0,length-1);
}


int main(){
    int arr[] = {1,2,3,4,5};
    test10(arr,0,5);
    printf("\n");
    for(int i=0;i<5;i++){
        printf("%d\t",arr[i]);
    }
    return 0;
}

11.两个有序表一起的中位数

//11
int test11(int a[],int b[],int length){
    int s1=0,s2=0,d1=length-1,d2=length-1,m1,m2;//首位 末位 中位
    while(s1 !=d1 || s2!=d2){
        m1 =(s1+d1)/2;
        m2 =(s2+d2)/2;
        printf("%d %d %d %d %d %d\n",s1,d1,m1,s2,d2,m2);
        if(a[m1]==b[m2]){
            return a[m1];
        }
        if(a[m1]<b[m2]) // 两个每次舍弃一样多
        {
            if((s1+d1)%2==0){   //若元素个数为奇数
                s1 = m1;    //舍弃a中位之前
                d2 = m2;    //舍弃中点之后的
            }
            else{
                s1 = m1+1;    //舍弃a中位之前
                d2 = m2;    //舍弃中点之后的
            }
        }
        else
        {
            if((s1+d1)%2==0){   //若元素个数为奇数
                d1 = m1;    //舍弃a中位之后
                s2 = m2;    //舍弃中点之前的
            }
            else{
                d1 = m1;    //舍弃a中位之后
                s2 = m2+1;    //舍弃中点之前的
            }
        }


    }
    return a[s1]<b[s2] ? a[s1]:b[s2];
}

12.判断无序数组中存在一个数存在个数大于2/n

int test12(int a[],int n){
    int num=1;
    int temp=a[0];
    for(int i=1;i<n;i++){

        if(a[i]==temp)
            num++;
        else if(num>=n/2)
            break;
        else
        {
            if(num>0)
            num--;
            else{        //注意num为0时更换元素
                num=1;
                temp=a[i];
            }
        }
     printf("%d %d %d\n",temp,a[i],num);
    }
    if(num>0){
        num=0;
        for(int i=0;i<n;i++){
            if(a[i] == temp){
                num++;
            }
        }
    }
     printf("最终%d  %d\n",temp,num);
    return num>(n/2) ? temp:-1;
}

int main(){
    int arr[] = {1,2,1,1};
    int num=test12(arr,4);
    printf("输出:%d",num);
    return 0;
}

13.无序数组寻找未出现最小正整数

int test13(int a[],int n){
    int i,b[n];
    memset(b,0,sizeof(int)*n); //void *memset(void *ptr, int value, size_t num);
    int j=1;
    for( i=0;i<n;i++){
        if(a[i]>0 &&a[i]<=n){
            b[a[i]-1]=1;
        }
    }
    for( i=0;i<n;i++){
        if(b[i]==0)
            break;
    }
    return i+1;
}
int main(){
    int arr[] = {-1,0,2,3};
    int num=test13(arr,4);
    printf("输出:%d",num);
    return 0;
}

14.三元组

// 三个一维数组各个数的差的和的最小值
int abs(int a){ //绝对值
    if(a<0)
        a=-a;
    return a;
}

bool num_min(int a,int b,int c){  //判断是否更小
    if(a<=b && a<=c)
        return true;
    return false;
}

int test14(int a[],int b[],int c[],int num1,int num2, int num3){
    // 三个一维数组 以及对应长度
    int i=0,j=0,k=0,temp=0;
    int min=abs(a[i]-b[j]) +abs(a[i]-c[k]) + abs(b[j]-c[k]); //赋初值最小距离

    while(i<num1 && j<num2 && k<num3){
        temp=abs(a[i]-b[j]) +abs(a[i]-c[k]) + abs(b[j]-c[k]);
        if(temp<min)
            min =temp;
        if(num_min(a[i],b[j],c[k]))
            i++;
        else if(num_min(b[j],a[i],c[k]))
            j++;
        else  k++;
    }
    return min;

}

int main(){
    int a[] = {-1,0,9};
    int b[] = {-25,-10,10,11};
    int c[] = {2,9,17,30,4};
    int num=test14(a,b,c,3,4,5);
    printf("输出:%d",num);
    return 0;
}

二.链表

1.链表基本操作

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>  //bool
#include <stddef.h>   // null
#include<malloc.h>      //malloc、free
typedef struct node{
    int data;
    struct node *next;
}node,*linklist;
//当你使用, *linklist; 这样的定义时,linklist 实际上就是指向 struct node 类型的指针。
//这种定义方式允许你在函数中直接使用 linklist 作为参数来操作链表,而不需要使用 *lt 来传递指针的指针
linklist init_list(){
    linklist lt = (linklist)malloc(sizeof(node)); // 创建头节点
    if(lt==NULL){
        printf("内存分配失败!\n");
        return NULL;
    }
    lt->next =NULL;
    return lt;  //如果不将头节点返回,你将失去对链表的访问权,无法进行后续的操作。
}

void print_list(linklist lt){
    lt = lt->next;
    if(lt==NULL){
        printf("当前为空表!\n");
        return ;
    }
    printf("链表元素中有:");
    while(lt)
    {
        printf("%d\t",lt->data);
        lt= lt->next;
    }
    printf("\n");
}

void free_list(linklist lt) {
    node* current = lt;
    while (lt) {
        current = lt;
        lt = lt->next;  //从前往后清空
        free(current);
    }
}

//linklist 定义函数与int void没区别只是方便让人明白这是对链表的操作
linklist head_insert(linklist lt){
    int n=0, e=0;
    printf("请输入要插入元素个数:");
    scanf("%d",&n);
    printf("\t请输入插入的元素:");
    for(int i=0;i<n;i++)
    {
        node*s = (node*)malloc(sizeof(node));
        scanf("%d",&e);
        s->data =e;         //头插法
        s->next = lt->next;
        lt->next = s;
    }
}

//尾插
linklist back_insert(linklist lt){
    int n=0, e=0;
    printf("请输入要插入元素个数:");
    scanf("%d",&n);
    printf("\t请输入插入的元素:");

    node *tail =lt;  //辅助尾指针
    for(int i=0;i<n;i++)
    {
        node*s = (node*)malloc(sizeof(node));
        scanf("%d",&e);
        s->data =e;         //尾插法
        tail->next = s;
        tail = s;

    }
    tail->next=NULL; //尾结点next指针设为NULL
    return lt;
}

//找第n个节点
linklist find_listnum(linklist lt,int n){
    if(n<1){
        printf("查找结点输入有误!\n") ;  // n表示 查找第几个元素
        return  NULL;
    }
    int j=1;
    node * s= lt->next;
    while(s!=NULL &&j<n){
        s=s->next;
        j++;
    }

    if(s== NULL ){
        printf("\t查找失败!超出链表长度\n");
        return NULL;
    }
    else{   //查找超出链表长度
        printf("\t 按位查找成功!第%d个元素为:%d\n",n,s->data);
        return s;
    }
}
//找值e
linklist find_listelem(linklist lt,int e){
    node * s= lt->next;
    int j=1;
    while(s!=NULL &&s->data!=e){
        s=s->next;
        j++;
    }

    if(s!=NULL ){
            printf("\t按值查找成功!第%d个元素为:%d\n",j,s->data);
        }
    else{   //查找超出链表长度
        printf("\t查找失败!超出链表长度\n");
    }
}

//插入到第几位
linklist insert_num(linklist lt,int e,int num){
    if(num<=0){
        printf("\t无效位置!\n");
        return lt;
    }
    int j=1;

    node* s =lt;
    while(s!=NULL &&j<num){   //j==num 或者遍历完
        j++;
        s=s->next;
    }

    if(j!=num || s==NULL ){
        printf("插入位置无效!\n");
        return lt;
    }
    node * temp=(node*)malloc(sizeof(node));
    temp->data=e;
    temp->next=s->next;
    s->next=temp;
    return lt;
}

//6.删除节点 (删第几个)
linklist delete_node(linklist lt,int n){
    if(n<=0){
        printf("无效位置!\n");
        return lt;
    }

    if(n==1 && lt->next!=NULL){ //删除第一个节点
        node *temp =lt->next;
        lt->next =temp->next;
        free(temp);
    }
    else{
        node* s =find_listnum(lt,n-1);
        if(s==NULL || s->next==NULL){
//这部分检查的是在找到要删除节点的前一个节点时,确保该前一个节点(s)存在,或者确保要删除的节点的下一个节点(s->next)存在
            printf("删除位置无效!\n");
            return lt;
        }
        node *temp =s->next;
        s->next =temp->next;
        free(temp);
    }
    return lt;
}

//7.表长
linklist linklist_length(linklist lt){
    int n=0;
//    node* temp =lt->next;
//    while(temp){
//        temp = temp->next;
//        n++;
//    }
    for(node* temp =lt->next;temp!=NULL;temp=temp->next){
        n++;
    }
    printf("\t 表长:%d \n",n);
    return n;
}
int main()
{
    linklist lt = init_list();  // 创建带头节点的链表
//    head_insert(lt);
//    print_list(lt);

    back_insert(lt);
    print_list(lt);

//    find_listnum(lt,2);
//
//    find_listelem(lt,2); //查找元素值

    insert_num(lt,10,3);
    print_list(lt);

//    delete_node(lt,1);  //会调用按位查找函数

    linklist_length(lt);
    print_list(lt);
    free_list(lt);
    return 0;
}

2.特殊链表

1.双链表

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>  //bool
#include <stddef.h>   // null
#include<malloc.h>      //malloc、free

typedef struct node{
    int data;
    struct node *prior,*next;
}dnode,*dlist; //双链表

dlist init_list(){
    dlist lt = (dlist)malloc(sizeof(dnode)); // 创建头节点
    if(lt==NULL){
        printf("内存分配失败!\n");
        return NULL;
    }
    lt->next =NULL;
    lt->prior = NULL;
    return lt;  //如果不将头节点返回,你将失去对链表的访问权,无法进行后续的操作。
}

dlist create_back(dlist lt){
    printf("请输入要插入节点个数:");
    int n =0,e=0;
    scanf("%d",&n);
    printf("\t 请依次输入输入插入的元素:");
    dnode*tail=lt;
    for(int i=0;i<n;i++){
        dnode*temp = (dnode*)malloc(sizeof(dnode));
        scanf("%d",&e);
        temp->data=e;
//        temp->next =NULL; // 我不喜欢这种写法 直接循环结束运行一次就行
        temp->prior =tail;  // 正确地设置新节点的前驱指针。
        tail->next = temp;  // 将新节点链接到上一个尾节点的后面。
        tail = temp;        // 更新尾节点为新节点。
    }
    tail->next=NULL;
    return lt;
}

void print_list(dlist lt){
    lt = lt->next;
    if(lt==NULL){
        printf("当前为空表!\n");
        return ;
    }
    printf("链表元素中有:");
    while(lt)
    {
        printf("%d\t",lt->data);
        lt= lt->next;
    }
    printf("\n");
}

void free_list(dlist lt) {
    dnode* current = lt;
    while (lt) {
        current = lt;
        lt = lt->next;  //从前往后清空
        free(current);
    }
}

dlist find_num(dlist lt,int n){
    if(n<1){
        printf("查找结点输入有误!\n") ;  // n表示 查找第几个元素
        return  NULL;
    }
    int j=1;
    dnode * s= lt->next;
    while(s!=NULL &&j<n){
        s=s->next;
        j++;
    }

    if(s== NULL ){
        printf("\t查找失败!超出链表长度\n");
        return NULL;
    }
    else{   //查找超出链表长度
        printf("\t 按位查找成功!第%d个元素为:%d\n",n,s->data);
        return s;
    }
}

dlist insert_num(dlist lt,int e,int num){
    if(num<=0){
        printf("无效位置!\n");
        return lt;
    }
    int j=1;
    dnode* s =lt;
    while(s!=NULL &&j<num){   //j==num 或者遍历完
        j++;                   // j=1,s为头节点起始 遍历完匹配到的情况下s为查找节点的前驱
        s=s->next;
    }
    if(j!=num || s==NULL ){
        printf("\t插入位置无效!\n");
        return lt;
    }
    dnode * temp=(dnode*)malloc(sizeof(dnode));
    temp->data=e;
//    temp->next=NULL;  //写不写一样

    temp->next=s->next;
    temp->prior=s;      // 正确地更新 temp 的前驱。
    if(s->next==NULL){  //注意特殊情况插入到表尾 则s->next==NULL
        s->next=temp;
        return lt;
    }
    s->next->prior = temp;    // 正确地更新下一个节点的前驱。
    s->next=temp;   // 正确地更新 s 的后继。
    return lt;
}

dlist delete_list(dlist lt,int n){
    if(n<=0){
        printf("\t无效位置!\n");
        return lt;
    }

    if(n==1 && lt->next!=NULL){     //不是空表情况下删除第一个节点
        dnode *temp =lt->next;
        lt->next =temp->next;
        if(temp->next!=NULL){       //如果不只有一个节点
          temp->next->prior  =lt ;
        }
                                    //如果只有一个节点 prior就不需要操作
        free(temp);
    }
    else{
        dnode* temp =find_num(lt,n-1);
        if(temp ==NULL || temp->next ==NULL){   //**啥两个都写现在还搞明白
//当你访问指针 temp 的成员 next 并检查它是否为 NULL 时,你是在检查当前节点的后继节点是否存在。
 //当你比较一个指针 temp 是否为 NULL 时,你是在检查这个指针是否指向了任何有效的内存地址。如果 temp 的值为 NULL,那么它并没有指向有效的内存,即它没有被分配任何内存空间。
            printf("\t超出链表长度范围!\n");
            return lt;
        }
//代码一
//不能free辅助节点,并且容易逻辑错误,例如 151代码在if语句前执行 ,
//逻辑错误:在代码一中,当 temp->next->next 为 NULL 时,你仍然尝试访问 temp->next->next->prior,
//这可能导致访问无效内存。此外,在释放被删除的节点后,你还尝试访问 temp->next,这可能会导致访问已释放内存,可能会引发未定义的行为。

//        if(temp->next->next!=NULL){     // 判断是否是删除的是否是最后一个节点,如果是那么最终链表尾结点next指向null 就不需要修改prior指针
//            temp = temp->next->next->prior;
//        }
//        temp->next =temp->next->next;


//代码二
        dnode* target =temp->next;
        temp->next = target->next;
        if(target->next!=NULL){
            target->next->prior =temp ;
        }
        free(target);

    }
    return lt;
}


int main()
{
    dlist lt = init_list();
    create_back(lt);
    print_list(lt);

//    insert_num(lt,5,1);
//    print_list(lt);

    delete_list(lt,2); //如果不是删除第一个节点会调用find_num()函数查找n前驱
    print_list(lt);
    return 0;
}

2.循环双链表

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>  //bool
#include <stddef.h>   // null
#include<malloc.h>      //malloc、free

typedef struct node{
    int data;
    struct node *prior,*next;
}cnode,*clist; //循环双链表

clist init_list(){
    clist lt = (clist)malloc(sizeof(cnode)); // 创建头节点
    if(lt==NULL){
        printf("内存分配失败!\n");
        return NULL;
    }
    lt->next =lt;
    lt->prior = lt;
    return lt;  //如果不将头节点返回,你将失去对链表的访问权,无法进行后续的操作。
}

bool empty(clist lt){
    return (lt->next ==lt);
}

void print_list(clist lt){
    if(!empty(lt)){
        cnode* temp =lt->next;
        printf("循环双链表顺序打印元素有:");
        while(temp!=lt)
        {
            printf("\t%d",temp->data);
            temp= temp->next;
        }
    }
    else{
        printf("\t当前为空表!\n");
    }
    printf("\n");
}

void print_reverse_list(clist lt){
    if(!empty(lt)){
        cnode* temp =lt->prior;
        printf("循环双链表逆序打印元素有:");
        while(temp != lt)
        {
            printf("\t%d",temp->data);
            temp= temp->prior;

        }
    }
    else{
        printf("\t当前为空表!\n");
    }
    printf("\n");
}

int length_list(clist lt){
    if(!empty(lt)){
        cnode* temp =lt;
        int num=0;
        while(temp->next!=lt)
        {
            temp= temp->next;
            num++;
        }
        return num;
    }
    return 0;
}

void free_list(clist lt) {
    cnode* current = lt;
    while (lt) {
        current = lt;
        lt = lt->next;  //从前往后清空
        free(current);
    }
}

clist back_create(clist lt){
    int n=0, e=0;
    printf("请输入要插入元素个数:");
    scanf("%d",&n);
    printf("\t请输入插入的元素:");

    cnode *temp =lt
    ;
    for(int i=0;i<n;i++)
    {
        cnode*s = (cnode*)malloc(sizeof(cnode));
        scanf("%d",&e);
        s->data =e;

        temp->next=s;
        s->prior=temp;
        temp=s;

    }
    lt->prior=temp;
    temp->next=lt;
    return lt;
}

clist insert_num(clist lt,int e ,int n){
    if(n<=0 || n>length_list(lt)+1){
        printf("\t无效位置!\n");
        return lt;
    }
    int j=1;    //为了找前驱所以赋值0
    cnode* s =lt;   //最好不要直接操作头指针 后续操作可能需要头指针
    while(s->next!=lt &&j<n){   //j== num 或者遍历完
        j++;                   // j=1,s为头节点起始 遍历完匹配到的情况下s为查找节点的前驱
        s=s->next;
    }
//    printf("\t %d %d  %d\n",s->data,j,length_list(lt));

    cnode * temp=(cnode*)malloc(sizeof(cnode));
    temp->data =e;
    if(n==1){       //插入表头
        temp->next= s->next;
        s->next->prior =temp;
        s->next =temp;
        temp->prior = s;
        return lt;
    }
    else if(n==length_list(lt)+1){  //插入表尾
        temp->prior=s;
        temp->next=lt;
        lt->prior=temp;
        s->next =temp;
        return lt;
    }
    //else
    temp->next = s->next;
    s->next->prior = temp;

    temp->prior=s;
    s->next=temp;
    return lt;
}

clist delete_num(clist lt,int n){
    if(n<1 || n>length_list(lt)){
        printf("   \t无效位置!\n");
        return lt;
    }
    cnode * temp =lt->next;
    if(n==1){
        if(length_list(lt)==1){
            lt->next=lt;
            lt->prior=lt;
        }
        else{
            temp->next->prior=lt ;
            lt->next =temp->next;
        }

    }
    else if(n==length_list(lt)){
        temp =temp->prior->prior;
        lt->prior = temp->prior;
        temp->prior->next=lt;
    }
    else{
        int j=1;
        while(temp!=lt &&j<n){
            temp=temp->next;
            j++;
        }
        temp->next->prior=temp->prior;
        temp->prior->next=temp->next;
    }
    free(temp);
    return lt;
}

int main(){
    clist lt = init_list();
    back_create(lt);
    print_list(lt);
    print_reverse_list(lt);

//    insert_num(lt,99,3);
//    print_list(lt);


    delete_num(lt,3);
    print_list(lt);

    free_list(lt);
    return 0;
}


3.静态链表

#include <stdio.h>
#include <stdlib.h>

#include <stdbool.h>  //bool
#include <stddef.h>   // null
#include<malloc.h>      //malloc、free


#define max 5
//typedef struct node{
//    int data;
//    int next;
//}
//创建时  struct node a[max];


typedef struct  node{
    int data;
    int next;
}node,jlist[max];
// 创建时  jlist a;


void init_list(jlist lt){
    lt[0].next=-1;
    for(int i=1;i<max;i++){
        lt[i].next=-2;
//        lt[i].data=NULL;
    }
    //测试next
//    for(int i=0;i<max;i++){
//        printf("\t %d",lt[i].next);
//    }
}

bool empty_list(jlist lt){
    return (lt[0].next==-1);
}

void print_list(jlist lt){
    if(lt[0].next!=-1){
        int i=0;
        printf("当前表中元素有:");
        while(lt[i].next!=-1)
            {
                i=lt[i].next;
                printf("\t%d ",lt[i].data);
            }
    }
    else{
        printf("\t当前为空表!\n");
    }
    printf("\n");
}

void create_list(jlist lt){
    printf("请输入要创建表长:");
    int n=0,e=0,i;
    scanf("%d",&n);
    printf("\t请依次输入元素:");
    lt[0].next=1;
    for( i=1;i<=n;i++){    //下标0不存储节点
        scanf("%d",&e);
        lt[i].data=e;
        lt[i].next=i+1;


    }
     lt[i-1].next=-1;  //第一个元素不存值 最后一个元素下标-1
//     for(int i=0;i<max;i++) //测试next
//        printf("\t %d",lt[i].next);
}

int find_num(jlist lt ,int n){
    if(n<=0 || n>=max){
        printf("\t 无效位置!\n");
        return -2;
    }
    else{
        if(!empty_list(lt)){
            int i=lt[0].next;
            int num=1;
            while(lt[i].next !=-1  && num<n){
                num++;
                i=lt[i].next;
            }
            if(n==num && lt[n].next!=-2){
                return i;  //找到这个位置 且该位置为实际存储元素节点
            }
        }
        return -1;      //空表 或超出表长
    }
}

int length_list(jlist lt){
    int i=0,count=0;
    while(lt[i].next!=-1)
    {
        i=lt[i].next;
        count++;
    }
    return count;
}

//将e插入到第n个位置上,与下标关系与+1
void  insert_num(jlist lt,int e,int n){
    if(length_list(lt)<1 || n>length_list(lt)+1 || n>=max){
        printf(" \t 无效位置!\n");
    }
    else{
        int i=0,count=0,j=0;
        while(lt[i].next!=-2){  //找到第一个空的位置
            i++;
        }
        lt[i].data = e;
        //    printf("\ti:%d\n",i); //测试
        while(lt[j].next!=-1 && count<n-1){
            j=lt[j].next;
            count++;
        }
        //    printf("\tj:%d count;%d\n",j,count);  //测试
        lt[i].next = lt[j].next;
        lt[j].next=i;
    }


}

//删除第n个元素
void delete_num(jlist lt,int n){
    if(n<1 || n>length_list(lt)){
        printf("\t 无效位置!\n");
    }
    else{
        int i=0,count=0;
        while(count<n-1){
            i=lt[i].next;
            count++;
        }
//        printf("i:%d count:%d \n",i,count); //测试
        count =lt[i].next;  //标记要删除的元素,count 变量后面用不到了懒得新建变量
        lt[i].next =lt[count].next;     //修改倒数第二个元素
        lt[count].next=-2; //删除该元素 逻辑上删除

    }
}
int main()
{
    jlist lt ;
    init_list(lt);
    create_list(lt);
    print_list(lt);

//    int n =find_num(lt,1);
//    if(n>-1){
//      printf("%d\n",lt[n].data);
//    }
//    else{
//        printf("超出!\n");
//    }

//    int m =length_list(lt);
//    printf("%d",m);

//    insert_num(lt,99,3);
//    print_list(lt);

    delete_num(lt,3);
    print_list(lt);

    return 0;
}

3. 链表算法

1.

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int data;
    struct node *next;
} node, *linklist;

linklist init_list() {
    return NULL;
}

linklist back_create(linklist lt) {
    int n = 0, e = 0;
    printf("请输入要插入元素个数:");
    scanf("%d", &n);
    printf("\t请输入插入的元素:");

    linklist tail = lt;
    for (int i = 0; i < n; i++) {
        linklist s = (linklist)malloc(sizeof(node));
        scanf("%d", &e);
        s->data = e;
        s->next = NULL;

        if (tail == NULL) {
            lt = s;
            tail = s;
        } else {
            tail->next = s;
            tail = s;
        }
    }
    return lt;
}

void print_list(linklist lt) {
    linklist current = lt;
    if (current == NULL) {
        printf("当前为空表!\n");
        return;
    }
    printf("链表元素中有:");
    while (current) {
        printf("%d\t", current->data);
        current = current->next;
    }
    printf("\n");
}

linklist delete_value(linklist lt, int x) {
    if (lt == NULL) {
        return NULL;
    }

    if (lt->data == x) {
        linklist temp = lt;
        lt = lt->next;
        free(temp);
        lt = delete_value(lt, x);
    } else {
        lt->next = delete_value(lt->next, x);
    }

    return lt;
}

void free_list(linklist lt) {
    linklist current = lt;
    while (current) {
        linklist temp = current;
        current = current->next;
        free(temp);
    }
}

int main() {
    linklist lt = init_list();
    lt = back_create(lt);
    print_list(lt);

    int x;
    printf("请输入要删除的值x:");
    scanf("%d", &x);
    
    lt = delete_value(lt, x);
    print_list(lt);

    free_list(lt);

    return 0;
}

2.

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int data;
    struct node *next;
} node, *linklist;

linklist init_list(){
    linklist lt = (linklist)malloc(sizeof(node)); // 创建头节点
    if(lt==NULL){
        printf("内存分配失败!\n");
        return NULL;
    }
    lt->next =NULL;
    return lt;  //如果不将头节点返回,你将失去对链表的访问权,无法进行后续的操作。
}

linklist back_create(linklist lt) {
    int n = 0, e = 0;
    printf("请输入要插入元素个数:");
    scanf("%d", &n);
    printf("\t请输入插入的元素:");

    linklist tail = lt;
    for (int i = 0; i < n; i++) {
        linklist s = (linklist)malloc(sizeof(node));
        scanf("%d", &e);
        s->data = e;
        s->next = NULL;

        tail->next = s;
        tail = s;
    }
    return lt;
}

void print_list(linklist lt) {
    linklist current = lt->next;
    if (current == NULL) {
        printf("当前为空表!\n");
        return;
    }
    printf("链表元素中有:");
    while (current) {
        printf("%d\t", current->data);
        current = current->next;
    }
    printf("\n");
}
//递归
linklist delete_value(linklist lt, int x) {
    if (lt == NULL) {
        return NULL;
    }

    if (lt->data == x) {
        linklist temp = lt;
        lt = lt->next;
        free(temp);
        lt = delete_value(lt, x);
    } else {
        lt->next = delete_value(lt->next, x);
    }

    return lt;
}
//非递归
void  delete_num(linklist lt,int num){
    linklist current = lt;
    while (current->next) {
        if (current->next->data == num) {
            linklist temp = current->next;
            current->next = temp->next;
            free(temp);
        } else {
            current = current->next;
        }
    }
}
void free_list(linklist lt) {
    linklist current = lt;
    while (current) {
        linklist temp = current;
        current = current->next;
        free(temp);
    }
}

int main() {
    linklist lt = init_list();
    lt = back_create(lt);
    print_list(lt);

    int x;
    printf("请输入要删除的值x:");
    scanf("%d", &x);

//    lt = delete_value(lt, x);
    delete_num(lt, x);
    print_list(lt);

    free_list(lt);

    return 0;
}

3.

void reverse_print(linklist lt){
//  reverse_print(lt);
//    reverse_print(lt->next); //传入的是头指针的next
    if(lt==NULL){
        return ;
    }
    reverse_print(lt->next);
    if(lt->data != -1){  //-1表示终止标志
        printf("\t%d",lt->data);
    }
}

void reverse_print1(linklist lt) {
    //如果传入的是头指针
//    linklist init_list() {
//    linklist lt = (linklist)malloc(sizeof(node));
//    if (lt == NULL) {
//        printf("内存分配失败!\n");
//        return NULL;
//    }
//    lt->data = -1;  // 设置头节点的data为-1,这一句需要修改
//    lt->next = NULL;
//    return lt;
//}
    if (lt == NULL) {   //判断整个链表是否为空。
        return;
    }
    if (lt->next != NULL) { //判断链表中是否只有头节点,没有实际的数据节点。
        reverse_print(lt->next);
    }
    if (lt->data != -1) {
        printf("\t%d", lt->data);
    }
}

4.

void delete_num(linklist lt){
    if(lt->next==NULL){
        return;
    }
    linklist minpre = lt;
    linklist temp =lt;      //辅助遍历节点
    linklist min =lt->next;     //最小值节点
    while(temp->next!=NULL){
        if(temp->next->data < min->data){
            minpre =temp;
            min=temp->next;
        }
        temp = temp->next;
    }
    minpre->next =min->next;    //删除最小值
    free(min);
}

5.

void reverse_list(linklist lt){
    if(lt->next==NULL | lt->next->next==NULL){ //空表或仅一个节点 不用额外逆置
        return ;
    }
    node* pre=NULL; //逆置后节点最后一个节点->next==NULL
    node* temp=lt->next;
    node* next=temp->next;
    while(next != NULL){
        temp->next = pre;  //断链 将到目前位置子链 逆序
        pre = temp;     //更新pre至下一个逆置节点前一个
        temp =next;
        next = next->next;
    }
    temp->next =pre;    //将最后一个节点连接前面所有逆置后的链表
    lt->next=temp;
}

6. 使单链表递增有序

void test6(linklist lt){
    node*temp =lt->next,*pre;   //pre 是辅助指针用于遍历已排序部分。
    node* next =temp->next;
    temp->next =NULL;   // 将 temp 所指向的节点作为已排序部分的头节点
    temp =next; // 更新 temp 为待排序部分的头节点
    while(temp!=NULL){
        next = temp->next;  // 暂存下一个待排序节点
        pre =lt;    // 初始化 pre 为头节点
        // 在已排序部分寻找插入位置  直接插入排序思想
        while(pre->next!=NULL && pre->next->data < temp->data)
            pre = pre->next;

        temp->next =pre->next;   // 将外排序第一个节点temp 插入到 pre 节点之后
        pre->next =temp;
        temp =next; // 更新 temp 为下一个待排序节点
    }
}

7. 删除带头节点单链表中节点值在a、b之间的节点

void test7(linklist lt,int min ,int max){
    node* pre=lt,*temp =lt->next;   //pre为保留的节点
    while(temp!=NULL){
        if(temp->data >= min && temp->data<= max){
            pre->next =temp->next;  //删除temp节点
            free(temp);
            temp =pre->next; //继续向后遍历
        }
        else{
            pre =temp;  //更新pre至temp节点
            temp = temp->next; //继续向后遍历
        }
    }
}

8.两个链表公共结点

//两个链表中的公共节点指的是节点的地址相同,即两个链表中的同一个节点被同时引用。
int list_length(linklist lt){
    int num=-1; //带头节点
    while(lt!=NULL){
        lt=lt->next;
        num+=1;
    }
    return num;
}

linklist test8(linklist a,linklist b){
    int n=list_length(a);
    int m=list_length(b);
    printf("%d %d\t",n,m);
    linklist list1,list2;  //1为长的 2为短的
    int num;
    if(n>m){
        list1 =a->next;
        list2 =b->next;
        num =n-m;
    }
    else{
        list1 =b->next;
        list2 =a->next;
        num=m-n;
    }
    //printf("测试一:%d %d %d\t",n,m,num);
    while(num--){
        list1 =list1->next;
    }
    while(list1!=NULL && list2!=NULL){
        //printf("测试:%d \n",list1->data);
        if(list1 == list2){   //返回的是不带头节点的公共节点单链表

            return list1;
        }
        else{
            list1 =list1->next;
            list2 =list2->next;
        }
    }
    return NULL;
}


int main() {
    linklist lt = init_list();  //第一条链表
    back_create(lt);
    print_list(lt);

    linklist lt2 = init_list(); //第二条单链表
    back_create(lt2);
    print_list(lt2);
    node *temp =lt2;
    while(temp->next!=NULL){
        temp=temp->next;
    }
    temp->next=lt->next;    //第二条单链表链接第一条链表
    printf("%d",temp->data);
     print_list(lt2);

    linklist lt3 =test8(lt,lt2);
    printf("公共节点:");
    while(lt3 != NULL){
        printf("\t%d",lt3->data);
        lt3=lt3->next;
    }
    free_list(lt);
    return 0;
}

9.依次删除最小值节点至空表

// 王道代码没考虑删除节点是第一个时的情况
void test9(linklist head){
    while(head->next!=NULL){
        node* pre =head;
        node* temp =pre->next;
        node* minpre=pre;   // 用于记录最小值节点的前驱
        node* min =temp;// 用于记录当前最小值节点
        while(temp->next != NULL){
            if(temp->next->data < min->data){
                minpre =temp;  //最小值的前驱
                min =temp->next;
            }
            temp =temp->next;
        }
        printf("\t%d",min->data);
        minpre->next =min->next;   //删除节点
        free(min);

    }
//    free(head);
}

10.单链表拆分成两个按照奇偶性

linklist test10(linklist lt){
    linklist lt2 =init_list(); //建立第二条链表 带头节点

    node * temp1=lt;
    node * temp2=lt2;
    node *temp=lt->next;
    lt->next=NULL;
    int count=1;
    while(temp!=NULL){
        if(count%2==0){    //偶数序号
            temp2->next =temp;
            temp2 =temp;
        }
        else{
            temp1->next=temp;
            temp1=temp;
        }
        temp =temp->next;
        count++;
    }
    temp2->next =NULL;
    temp1->next =NULL;
    return lt2;
}

int main() {
    linklist lt = init_list();  //第一条链表
    back_create(lt);
    print_list(lt);

    node*lt2 =test10(lt);
    print_list(lt);
    print_list(lt2);
    return 0;
}

11.拆表

linklist test11(linklist lt){
    linklist lt2= init_list(); //建立第二条链表 带头节点

    node*temp =lt->next; //遍历辅助节点
    node*temp1 =lt;   //原链表辅助节点
    node*temp2 =lt2;    //第二条链表辅助节点
    node*temp3;     //辅助保存移动节点的原本位置上的后驱节点
    while(temp!=NULL){
        temp1->next=temp;
        temp1 =temp;
        temp =temp->next;
        if(temp!=NULL){
            temp3 =temp->next;  //保存要移动节点的后驱
            temp->next =temp2->next;
            temp2->next=temp;   //插入lt2
            temp =temp3;        //更新temp
        }
    }
    temp1->next=NULL;  //如果不赋值NULL ,将连接第二条链表的第一个节点
    return lt2;
}

12.递增有序去重

void test12(linklist lt){
    node*temp =lt->next;
    node*p; //辅助删除节点
    if(temp==NULL){
        return ;
    }
    while(temp->next!=NULL){
        p= temp->next;
        if(temp->data == p->data){
            temp->next=p->next; //删除元素
            free(p);
        }
        else{
            temp = temp->next;
        }
    }

}

13.两条递增链表合并成一条从大到小的链表

void test13(linklist lt,linklist lt2){
    node *temp1=lt->next;
    node *temp2 =lt2->next;
    node *temp3 =lt;  //不直接操作lt,最终返回的是合并操作后的链表一
    temp3->next=NULL;//头插法
    node*temp4;     //因为不直接操作头节点 ,多一个辅助节点 ,保证操作表后续节点还能操作
    while(temp1!=NULL && temp2!=NULL){
        if(temp1->data <= temp2->data){
            temp4=temp1->next;  //不断链
            temp1->next=temp3->next;
            temp3->next =temp1;
            temp1 =temp4;
        }
        else{
            temp4=temp2->next;  //不断链
            temp2->next=temp3->next;
            temp3->next =temp2;
            temp2 =temp4;
        }
    }
    if(temp1==NULL){    //最后到操作第一条链表,如果链表二长 表一空了 赋值,这样后续就不用分情况
        temp1 =temp2;
    }
    while(temp1!=NULL){
        temp4=temp1->next;  //不断链
        temp1->next=temp3->next;
        temp3->next =temp1;
        temp1 =temp4;
    }
    free(lt2);
}

14.两链表公共元素不破坏原表(懒得写)

15.两链表公共元素 (目的表为表一)

linklist test15(linklist lt,linklist lt2){
    node *temp1=lt->next;   //将表一表二与头节点断链 ,这么理解
    node *temp2 =lt2->next;
    node*temp3=lt;     //始终为表一表尾,尾插法
    node*temp4;
    while(temp1!=NULL && temp2!=NULL) //当存在一条表遍历完
    {
        if(temp1->data <temp2->data){
            temp4=temp1;
            temp1 =temp1->next;   //更新
            free(temp4);    //删除不需要的节点
        }
        else if(temp1->data >temp2->data){
            temp4=temp2;
            temp2 =temp2->next;   //更新
            free(temp4);    //删除不需要的节点
        }
        else{
            temp3->next=temp1;
            temp3=temp1;
            temp1=temp1->next;
        }
    }
    temp3->next=NULL;
    while(temp1!=NULL){
        temp4=temp1;
        temp1 =temp1->next;   //更新
        free(temp4);    //删除不需要的节点
    }
    while(temp2!=NULL){
        temp4=temp2;
        temp2 =temp2->next;   //更新
        free(temp4);    //删除不需要的节点
    }
    free(lt2);
    return lt;
}

16.判断是否是连续子序列

int test16(linklist list1, linklist list2) {
    node *p1 = list1->next;  // 表一指针
    node *p2 = list2->next;  // 表二指针
    node *start = NULL;      // 当前可能的起点

    while (p1 && p2) {
        if (p1->data == p2->data) {
            if (!start) {
                start = p1;  // 记录当前可能的起点
            }
            p1 = p1->next;  // 匹配成功,继续匹配下一个节点
            p2 = p2->next;
        } else {
            p1 = start->next;  // 匹配失败,将表一指针回溯到起点的下一个节点
            p2 = list2->next;  // 表二指针回到起点
            start = NULL;      // 重置起点
        }

        if (!p2) {
            printf("\t是\n");
            return 1;  // 表示成功匹配了整个表二
        }
    }

    printf("\t不是\n");
    return 0;  // 表二不是表一的连续子序列
}

17.循环双链表判断是否对称

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>  //bool
#include <stddef.h>   // null
#include<malloc.h>      //malloc、free
typedef struct node{
    int data;
    struct node *prior,*next;
}cnode,*clist; //循环双链表

clist init_list(){
    clist lt = (clist)malloc(sizeof(cnode)); // 创建头节点
    if(lt==NULL){
        printf("内存分配失败!\n");
        return NULL;
    }
    lt->next =lt;
    lt->prior = lt;
    return lt;  //如果不将头节点返回,你将失去对链表的访问权,无法进行后续的操作。
}
bool empty(clist lt){
    return (lt->next ==lt);
}

void print_list(clist lt){
    if(!empty(lt)){
        cnode* temp =lt->next;
        printf("循环双链表顺序打印元素有:");
        while(temp!=lt)
        {
            printf("\t%d",temp->data);
            temp= temp->next;
        }
    }
    else{
        printf("\t当前为空表!\n");
    }
    printf("\n");
}
clist back_create(clist lt){
    int n=0, e=0;
    printf("请输入要插入元素个数:");
    scanf("%d",&n);
    printf("\t请输入插入的元素:");

    cnode *temp =lt;
    for(int i=0;i<n;i++)
    {
        cnode*s = (cnode*)malloc(sizeof(cnode));
        scanf("%d",&e);
        s->data =e;

        temp->next=s;
        s->prior=temp;
        temp=s;

    }
    lt->prior=temp;
    temp->next=lt;
    return lt;
}

int test17(clist lt){
    cnode*temp1=lt->next;
    cnode*temp2=lt->prior;
    while(temp1!=temp2 && temp1->next!= temp2){
        if(temp1->data ==temp2->data){
            temp1=temp1->next;
            temp2=temp2->prior;
        }
        else{
            printf("\t 失败\n");
            return 0;
        }
    }
    printf("\t 是\n");
    return 1;
}
int main(){
    clist lt = init_list();
    back_create(lt);
    print_list(lt);
    test17(lt);
    print_list(lt);
    return 0;
}

18.合并单循环链表 (我写的双循序)

//双顺序合并
void test18(clist lt,clist lt2){
    cnode*temp1 =lt->prior; //第一个链表的尾元素

    cnode*temp2 =lt2->prior; //第二个链表的尾元素

    temp1->next=lt2->next;
    lt->prior=temp2;

    temp2->next=lt;
    lt2->next->prior=temp1;

    free(lt2);
}

19.

//没写单链表 抄书
void test19(linklist lt){
    node *p,*pre,*min,*minpre;
    while(lt->next !=NULL){ //判断表不为空
        p=lt->next;
        pre=lt;
        min =p;
        minpre= pre;
        while(p!=lt){
            if(p->data < min->data){
                min =p;
                minpre= pre;
            }
            pre =p;
            p=p->next;
        }
        printf("\t %d ",min->data);
        minpre->next = min->next;   //逻辑删除最小值节点
        free(min);      //物理删除
    }
    free(lt);
}

21. 判断有环 (书上代码c+++)

linklist test21(linklist lt){
    node* fast =lt;
    node* slow =lt;
    while(fast!=NULL && fast->next!=NULL){
        slow =slow->next;
        fast =fast->next->next;
        if(slow == fast) break; //有环
    }
    if(fast==NULL || fast->next==NULL)
        return NULL;
    node *p1=lt; node*p2 =slow;
    while(p1!=p2){          //如果相交 相交与环部分中节点群 中的一个 ,不一定尾结点 或者尾结点指针指向的节点
        p1 = p1->next;
        p2 = p2->next;
    }
    return p1;
}

22.寻找单链表倒数第k个节点

//-------------------------- 二.单链表基本操作 的定义与使用
int test22(linklist lt, int num){
    node *pre=lt;
    node *p=lt;
    int count=0;
    while(p!=NULL){
        p=p->next;
        count++;
        if(count ==num) break;
    }
    if(count <num || num<1){
        return 0;
    }
    while(p!=NULL){   //最后一个节点 而不是最后一个节点 next指针
        pre =pre->next;
        p =p->next;
    }
    return pre;
}


int main()
{
    linklist lt = init_list();  // 创建带头节点的链表
//    head_insert(lt);
//    print_list(lt);

    back_insert(lt);
    print_list(lt);

    node * p=test22(lt,2);
    printf("%d",p->data);
    free_list(lt);
    return 0;
}

23.查找两单链表公共序列首节点

linklist test23(linklist lt,linklist lt2){
    int len1=linklist_length(lt);
    int len2=linklist_length(lt2); //代码大意即先将两指针移动到尾结点等长
//    printf("%d %d\n",len1,len2);
    node*temp1=lt;
    node*temp2=lt2;
    for(temp1;len1>len2;len1--){
        temp1=temp1->next;
    }
    for(temp2;len1<len2;len2--){
        temp2=temp2->next;
    }
    while(temp1->next !=NULL && temp1->next!=temp2->next){ //当temp是尾结点 或者temp1 和temp2指针为相同地址
        temp1=temp1->next;
        temp2=temp2->next;
    }
    return temp1->next;
}

int main()
{
    linklist lt = init_list();  // 创建带头节点的链表
    back_insert(lt);
    print_list(lt);

    linklist lt2 = init_list();
    back_insert(lt2);
    node*temp=lt2;
    while(temp->next!=NULL){
        temp= temp->next;
    }
    temp->next=lt->next;        //测试案例 ,不会模拟公共,只好第二条末尾插入第一条链表
    print_list(lt2);

    node * p=test23(lt,lt2);
    printf("%d",p->data);
    free_list(lt);
    return 0;
}

24.去重

linklist test24(linklist lt,int n){ // n表示链表中所有节点值绝对值都不超过n ,链表结构就懒得换名 Link 还是用next
    int nums[n];
    for(int i=0;i<n;i++){
        nums[i]=0;
    }
    int num;
    node *temp=lt;          //因为要删除 所以操作中 temp->next
    node *freetemp; //用来删除节点的辅助节点
    while(temp->next !=NULL){       //当是最后一个节点
        num =temp->next->data >0 ? temp->next->data :-temp->next->data; //保存该节点值得绝对值
        printf("\t %d",num);
        if(nums[num]==0){   //第一次出现
            nums[num] =1;
            temp =temp->next;
        }
        else{   //该值已经存在
            freetemp =temp->next;
            temp->next =freetemp->next;  //删除节点 , 不向下更新temp,只是temp next指针变化
            free(freetemp); //物理删除
        }
    }
}

25.链表位置改变

void test25(linklist lt){
    node*temp1=lt;
    node*temp2=lt;
    node*temp3=(node*)malloc(sizeof(node)) ;
    node*temp4=(node*)malloc(sizeof(node)) ;

    while(temp2->next!=NULL){   //temp1 为中点
        temp1=temp1->next;
        temp2=temp2->next;
        if(temp2->next !=NULL) temp2 =temp2->next;
    }                   //如果长度为奇数 原中点节点就是修改后尾结点,那么两个链表中点直接插入表尾;如果是偶数 中点后一个元素开始到表尾长度为一半,中点后链表和前一半链表刚好前一个后一个构成新链表;
    temp2 =temp1->next; //综上,将得到的中点后一个节点赋值给temp2
    temp1->next =NULL; //前一半与后一半断开
    temp3->next=NULL;           //temp3相当于是头节点 将后半部分尾插至temp3后面
    while(temp2!=NULL){ //逆置后半部分
        temp4=temp2->next;
        temp2->next=temp3->next;
        temp3->next = temp2;
        temp2=temp4;
    }
    temp1=lt->next; //temp1为链表前半部分第一个节点
    temp2=temp3->next;  //temp2为后半部分第一个节点
    while(temp2!=NULL){
        temp4=temp2->next;      //将后半部分第一个节点插入前半部分该在的位置
        temp2->next=temp1->next;
        temp1->next=temp2;
        temp1=temp2->next;  //更新前半分指针
        temp2=temp4;    //更新后半部分指针
    }
}

---------后续都是链接 点两次---------------------

三.栈、队列、数组

四.串

五.树

六.图

七.查找

八.排序

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值