第二章 线性表

顺序表

Microsoft Visual Studio 2012实现:
头文件:顺序表基本操作函数.h
源文件:顺序表.cpp

顺序表基本操作函数.h
#include<iostream>

using namespace std;

const int LIST_INIT_SIZE=100;
const int LIST_INCREMENT=100;

typedef struct{
    int *elem;
    int len;
    int listsize;
}sqlist;

void error_message(char *s){
    cout<<s<<endl;
    exit(1);
}

void increment(sqlist &L){
    int *p=new int[L.listsize+LIST_INCREMENT];
    if(p==nullptr)error_message("内存分配失败");
    for(int i=0;i<L.len;i++)p[i]=L.elem[i];
    delete[]L.elem;
    L.elem=p;
    L.listsize+=LIST_INCREMENT;
    delete[] p;
    p=nullptr;
}

void init_sqlist(sqlist &L){
    L.elem=new int[LIST_INIT_SIZE];
    L.len=0;
    L.listsize=LIST_INIT_SIZE;
}

int locate_elem_sq(sqlist L,int e){
    int i;//i表示位置,从1开始
    for(i=1;i<=L.len && L.elem[i-1]!=e;++i);
    if(i<=L.len)return i;
    return 0;
}
//插入第i个元素之前,i从1开始
void insert_sqlist(sqlist &L,int i,int e){
    if(i<1 || i>L.len+1)error_message("i值非法");
    if(L.len>=L.listsize)increment(L);
    for(int j=L.len-1;j>=i-1;j--)
        L.elem[j+1]=L.elem[j];
    L.elem[i-1]=e;
    L.len++;
}

void delete_sqlist(sqlist &L,int i,int &e){
    if(i<1 || i>L.len)error_message("i值非法");
    e=L.elem[i-1];
    for(int j=i;j<L.len;j++)
        L.elem[j-1]=L.elem[j];
    L.len--;
}

void destroy_sqlist(sqlist &L){
    delete[] L.elem;
    L.elem=nullptr;
    L.len=0;
    L.listsize=0;
}
顺序表.cpp
#include<iostream>
#include<cstdlib>
#include"顺序表基本操作函数.h"

using namespace std;

void print(sqlist L){
    for(int i=0;i<L.len;i++){
        if(i==0)cout<<L.elem[i];
        else cout<<" "<<L.elem[i];
    }
    cout<<endl;
}

//例2.1已知两个集合A,B,求A=AUB
void _union(sqlist &A,sqlist &B){
    for(int i=0;i<B.len;i++){
        if(!locate_elem_sq(A,B.elem[i]))
            insert_sqlist(A,A.len+1,B.elem[i]);
    }
}
//例2.2把非纯集合C的纯集合用D表示
void purify_set(sqlist &A,sqlist &B){
    int cnt=1;
    for(int i=0;i<A.len;i++){
        if(!locate_elem_sq(B,A.elem[i]))
            insert_sqlist(B,cnt++,A.elem[i]);
    }
}

//例2.3判断A,B两个集合是否相等
bool isequal(sqlist A,sqlist B){
    if(A.len!=B.len)return false;
    sqlist C;
    init_sqlist(C);
    for(int i=0;i<A.len;i++)
        insert_sqlist(C,i+1,A.elem[i]);
    bool flag=true;
    for(int i=0;i<B.len;i++){
        int loc=locate_elem_sq(C,B.elem[i]);
        if(loc){
            int tmp;
            delete_sqlist(C,loc,tmp);
        }
        else{
            flag=0;
            break;
        }
    }
    if(C.len==0 && flag){
        destroy_sqlist(C);
        return true;
    }
    else{
        destroy_sqlist(C);
        return false;
    }
}
//例2.4比较两个集合的字典序大小,类似于字符串大小比较,A>B返回1,A=B返回0,A<B返回-1
int compare(sqlist A,sqlist B){
    for(int i=0;i<A.len && i<B.len;i++){
        if(A.elem[i]>B.elem[i])return 1;
        else if(A.elem[i]<B.elem[i])return -1;
    }
    if(A.len>B.len)return 1;
    else if(A.len==B.len)return 0;
    else return -1;
}
//例2.5交换E(E1,E2,E3,E4)两个序列的位置,(1,2,)(3,4,5)变为(3,4,5,)(1,2)
//例2.5(方案一)
void exchange1(sqlist &A,int m,int n){
    int *p=new int[m+n+5];
    if(p==nullptr)error_message("内存分配失败");
    int cnt=0;
    for(int i=m;i<m+n;i++)
        p[cnt++]=A.elem[i];
    for(int i=0;i<m;i++)
        p[cnt++]=A.elem[i];
    for(int i=0;i<A.len;i++){
        A.elem[i]=p[i];
    }
    delete[] p;
    p=nullptr;
}
//例2.5(方案二)先写右移一位的函数,再执行n次,达到效果
void right_move(sqlist &A){
    int tmp=A.elem[A.len-1];
    for(int i=A.len-2;i>=0;i--)
        A.elem[i+1]=A.elem[i];
    A.elem[0]=tmp;
}
void exchange2(sqlist &A,int m,int n){
    for(int i=0;i<n;i++)
        right_move(A);
}
//例2.5(方案三)一步到位右移n位
void exchange3(sqlist &A,int m,int n){
    int *p=new int[m+n+5];
    if(!p)error_message("内存分配失败");
    for(int i=0;i<A.len;i++)
        p[(i+n)%(m+n)]=A.elem[i];
    int tmp;
    while(A.len){
        delete_sqlist(A,A.len,tmp);
    }
    for(int i=1;i<=m+n;i++)
        insert_sqlist(A,i,p[i-1]);
    delete[] p;p=nullptr;
}
//例2.5(方案四)逆置三次(类似于第一章 解题指导与示例7的方案四算法)
void invert(sqlist &A,int i,int j){
    for(int k=i;k<=(i+j)/2;k++)
        swap(A.elem[i+j-k],A.elem[k]);
}
void exchange4(sqlist &A,int m,int n){
    invert(A,0,m-1);
    invert(A,m,m+n-1);
    invert(A,0,m+n-1);
}
//把两个非减表合并为一个非减表
void merge_sqlist(sqlist L1,sqlist L2,sqlist &L){
    int i=0,j=0;
    int cnt=1;
    while(i<L1.len && j<L2.len){
        if(L1.elem[i]<L2.elem[j]){
            insert_sqlist(L,cnt++,L1.elem[i++]);
        }
        else{
            insert_sqlist(L,cnt++,L2.elem[j++]);
        }
    }
    while(i<L1.len)insert_sqlist(L,cnt++,L1.elem[i++]);
    while(j<L2.len)insert_sqlist(L,cnt++,L2.elem[j++]);
}

//向有序表(非减)中插入元素后,仍然有序
void sqlist_insert_order(sqlist &L,int e){
    int i=L.len-1;
    while(i>=0 && e<L.elem[i]){
        L.elem[i+1]=L.elem[i];
        i--;
    }
    L.elem[i+1]=e;
    L.len++;
}

//将有序顺序表中重复的元素,保留一个,其余删除
void sqlist_purify(sqlist &L){
    int i=-1,j=0;
    while(j<L.len){
        if(j==0 || L.elem[i]!=L.elem[j])
            L.elem[++i]=L.elem[j];
        j++;
    }
    L.len=i+1;
}

//筛选顺序表中的非负数
void sqlist_filter(sqlist &L){
    int i=0,j=0;
    for(;i<L.len;i++){
        if(L.elem[i]>=0){
            if(i!=j)
                L.elem[j]=L.elem[i];
            j++;
        }
    }
    L.len=j;
}

//删除线性表中第i个元素起的k个元素
void sqlist_delete_k(sqlist &L,int i,int k){
    if(!(i>=1 && i<=L.len && k>=0 && i-1+k<=L.len))
        error_message("删除元素的位置或者个数错误");
    int e;
    while(k--){
        delete_sqlist(L,i,e);
    }
}

int main()
{
    int a[5]={1,2,3};
    int b[5]={4,5};
    int c[10]={1,2,2,3,4,5,5,6,7,7};
    sqlist A,B,C,D,E1,E2,E3,E4,F,G;
    init_sqlist(A);
    init_sqlist(B);
    init_sqlist(C);
    init_sqlist(D);
    init_sqlist(E1);init_sqlist(E2);init_sqlist(E3);init_sqlist(E4);
    init_sqlist(F);
    init_sqlist(G);

    for(int i=1;i<=3;i++)insert_sqlist(A,i,a[i-1]);
    for(int i=1;i<=2;i++)insert_sqlist(B,i,b[i-1]);
    for(int i=1;i<=10;i++)insert_sqlist(C,i,c[i-1]);
    for(int i=1;i<=5;i++)insert_sqlist(E1,i,i);
    for(int i=1;i<=5;i++)insert_sqlist(E2,i,i);
    for(int i=1;i<=5;i++)insert_sqlist(E3,i,i);
    for(int i=1;i<=5;i++)insert_sqlist(E4,i,i);
    for(int i=1;i<=3;i++)insert_sqlist(F,i,i+2);

    //例2.1求两个集合的并集
    cout<<"A: ";print(A);
    cout<<"B: ";print(B);
    _union(A,B);
    cout<<"A(AUB): ";
    print(A);

    cout<<endl;
    //例2.2把非纯集合C的纯集合用集合D表示
    cout<<"C(非纯集合): ";print(C);
    purify_set(C,D);
    cout<<"D(C的纯集合): ";
    print(D);

    cout<<endl;
    //例2.3判断A,B两个集合是否相同
    cout<<"A"<<(isequal(A,B)?"=":"!=")<<"B"<<endl;
    cout<<"B"<<(isequal(B,B)?"=":"!=")<<"B"<<endl;

    cout<<endl;
    //例2.4比较A,C两个集合字典序的大小,类似于字符串比较大小
    int tmp=compare(A,C);
    if(tmp==1)cout<<"A>C"<<endl;
    else if(tmp==0)cout<<"A=C"<<endl;
    else cout<<"A<C"<<endl;

    cout<<endl;
    //例2.5交换E(E1,E2,E3,E4)两个序列的位置,(1,2,)(3,4,5)变为(3,4,5,)(1,2)
    //例2.5(方案一)
    exchange1(E1,2,3);
    print(E1);
    //例2.5(方案二)
    exchange2(E2,2,3);
    print(E2);
    //例2.5(方案三)一步到位右移n位
    exchange3(E3,2,3);
    print(E3);
    //例2.5(方案四)逆置三次(类似于第一章 解题指导与示例7的方案四算法)
    exchange4(E4,2,3);
    print(E4);

    cout<<endl;
    //把两个有序的顺序表B,F合并成一个有序的顺序表G
    cout<<"B,F有序合并:"<<endl;
    merge_sqlist(B,F,G);
    cout<<"G: ";
    print(G);

    //G中插入2,仍然有序
    cout<<"G中插入2,仍然有序"<<endl;
    cout<<"G: ";
    sqlist_insert_order(G,2);
    print(G);

    //去除G中的重复元素
    cout<<"把G净化为集合,G: ";
    sqlist_purify(G);
    print(G);

    //G中插入几个负数
    for(int i=5;i<=8;i++)
        insert_sqlist(G,i,i-100);
    cout<<"G插入几个负数后,G:";
    print(G);
    cout<<"筛出G中的负数后,G:";
    sqlist_filter(G);
    print(G);

    //删除G中第2个元素开始的2个元素
    cout<<"删除G中第2个元素开始的2个元素后,G: ";
    sqlist_delete_k(G,2,2);
    print(G);

}



链表

Microsoft Visual Studio 2012实现:
头文件:链表.h
源文件:链表.cpp
输入方式:重定向,文件内容如下,
5 4 3 2 1
1 2 3 3 3 4 5
7 8 9
12 13 14 15 16 17

链表.h
#include<iostream>
#include<string>

using namespace std;

typedef int elemtype;

typedef struct Node{
    elemtype data;
    struct Node *next;
}node,*linklist;

//定义双向链表类型
typedef struct dnode{
    elemtype data;
    struct dnode *prior,*next;
}dnode,*dlinklist;

//错误提示函数
void error_message(string s){
    cout<<s<<endl;
    exit(-1);
}

//头插法建立链表
void create_linklist1(linklist &L,int n){
    L=new node;
    if(L==nullptr)error_message("分配内存失败");
    L->next=nullptr;
    for(int i=0;i<n;i++){
        node *p=new node;
        if(p==nullptr)error_message("分配内存失败");
        cin>>p->data;
        p->next=L->next;L->next=p;
    }
}

//尾插法建立链表
void create_linklist2(linklist &L,int n){
    L=new node;
    if(L==nullptr)error_message("分配内存失败");
    L->next=nullptr;
    node *rear=L;
    for(int i=0;i<n;i++){
        node *p=new node;
        if(p==nullptr)error_message("分配内存失败");
        p->next=nullptr;//忘记写这句,程序崩溃!
        cin>>p->data;
        rear->next=p;
        rear=p;//rear始终指向链表的最后一个节点
    }
}


//尾插法建立双向循环链表
void create_dlinklist2(dlinklist &L,int n){
    L=new dnode;
    if(L==nullptr) error_message("分配内存失败");
    L->next=nullptr;
    L->prior=nullptr;
    dnode *rear=L;
    for(int i=0;i<n;i++){
        dnode *p=new dnode;
        if(p==nullptr) error_message("分配内存失败");
        cin>>p->data;
        p->next=nullptr;
        p->prior=rear;
        rear->next=p;
        rear=p;
    }
    rear->next=L;
}

//销毁链表
void linklist_destroy(linklist &L){
    node *p=nullptr,*head=L->next;
    while(head){
        p=head->next;
        delete head;
        head=p;
    }
}

//清空链表
void linklist_clear(linklist &L){
    node *p=L->next;
    node *q=nullptr;
    while(p){
        q=p->next;
        delete p;
        p=q;
    }
    L->next=nullptr;
}

//遍历链表,输出所有数据值
void linklist_traverse(linklist L){
    node *p=L->next;
    while(p!=nullptr){
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}

//遍历双向链表,输出所有数据值
void dlinklist_traverse(dlinklist L,int n){
    dnode *p=L->next;
    int i=0;
    while(p!=nullptr && i<n){
        cout<<p->data<<" ";
        p=p->next;
        i++;
    }
    cout<<endl;
}

//求链表长度
int linklist_length(linklist L){
    node *p=L->next;
    int cnt=0;
    while(p!=nullptr){
        cnt++;
        p=p->next;
    }
    return cnt;
}

//查找链表中第i个元素,并存放在e中
bool get_elem(linklist L,int i,elemtype &e){
    if(i<1 || i>linklist_length(L))return false;
    node *p=L;
    while(i--){
        p=p->next;
    }
    e=p->data;
    return true;
}

//查找链表中第一个与e相等的节点的位置
int locate_elem(linklist L,elemtype e){
    int i=1;
    node *p=L->next;
    while(p!=nullptr && p->data!=e){
        i++;
        p=p->next;
    }
    if(p!=nullptr)return i;
    else return 0;
}

//查找链表中与e相等的节点的个数
int e_num(linklist L,elemtype e){
    int cnt=0;
    node *p=L->next;
    while(p){
        if(p->data==e)cnt++;
        p=p->next;
    }
    return cnt;
}

//在链表的第i个元素之前插入新节点
void linklist_insert(linklist &L,int i,elemtype e){
    node *pi=L;
    int j=0;
    while(pi && j<i-1){
        j++;
        pi=pi->next;
    }
    if(!pi || j>i-1){   //若pi=nullptr,则插入节点的位置大于了链表的长度加1,j>i-1,则i<=1
                        //i=1,表明插入第一个位置,i<1,表明插入位置不存在
        error_message("插入位置不存在");

    }
    node *p=new node;
    if(p==nullptr)error_message("内存分配失败");
    p->data=e;
    p->next=pi->next;
    pi->next=p;
}

//双向链表的第i个元素之前插入新节点
void dlinklist_insert(dlinklist &L,int i,elemtype e){
    dnode *pi=L;
    int j=0;
    while(pi && j<i-1){
        j++;
        pi=pi->next;
    }
    if(!pi || j>i-1){
        error_message("插入位置不存在");
    }
    dnode *p=new dnode;
    if(p==nullptr) error_message("内存分配失败");
    p->data=e;
    p->next=pi->next;
    p->prior=pi;
    pi->next->prior=p;
    pi->next=p;
}

//逆置链表
void linklist_reverse(linklist &L){
    node *p=L->next;
    node *post=nullptr;
    node *pre=nullptr;
    while(p){
        post=p->next;
        p->next=pre;
        pre=p;
        p=post;
    }
    L->next=pre;
}

//删除链表中第i个节点,保存在e中
void linklist_delete(linklist &L,int i,elemtype &e){
    node *p=L;
    int j=0;
    while(p->next && j<i-1){
        p=p->next;
        j++;
    }
    if(!p->next || j>i-1){          //若p->next=nullptr,则删除的节点要么不存在,要么是nullptr,j>i-1表明i<=0
        error_message("要删除的元素位置错误");
    }
    node *tmp=p->next;
    e=tmp->data;
    p->next=tmp->next;
    delete tmp;
}

//删除链表中的偶数序号的结点
void linklist_delete_even(linklist &L){
    node *p=L->next;
    node *q=nullptr;
    while(p && p->next){
        q=p->next;
        p->next=q->next;
        p=q->next;
        delete q;
    }
}

//删除双向循环链表中的第i个元素,保存在e中
void dlinklist_delete(dlinklist &L,int i,elemtype &e){
    dnode *p=L;
    int j=0;
    while(p->next && j<i){
        p=p->next;
        j++;
    }
    if(!p || j>i){
        error_message("要删除的元素位置错误");
    }
    e=p->data;
    p->prior->next=p->next;
    p->next->prior=p->prior;
    delete p;
}

//两个有序链表合并成一个有序表
void linklist_merge(linklist L1,linklist L2,linklist &L3){
    L3=new node;
    if(L3==nullptr)
        error_message("内存分配失败");
    L3->next=nullptr;
    node *p1=L1->next;
    node *p2=L2->next;
    node *rear=L3;
    while(p1 && p2){
        if(p1->data < p2->data){
            node *tmp=new node;
            if(tmp==nullptr)
            error_message("内存分配失败");
            tmp->next=nullptr;
            tmp->data=p1->data;
            rear->next=tmp;
            rear=tmp;
            p1=p1->next;
        }
        else{
            node *tmp=new node;
            if(tmp==nullptr)
            error_message("内存分配失败");
            tmp->next=nullptr;
            tmp->data=p2->data;
            rear->next=tmp;
            rear=tmp;
            p2=p2->next;
        }
    }
    while(p1){
        node *tmp=new node;
        if(tmp==nullptr)
        error_message("内存分配失败");
        tmp->next=nullptr;
        tmp->data=p1->data;
        rear->next=tmp;
        rear=tmp;
        p1=p1->next;    
    }
    while(p2){
        node *tmp=new node;
        if(tmp==nullptr)
        error_message("内存分配失败");
        tmp->next=nullptr;
        tmp->data=p2->data;
        rear->next=tmp;
        rear=tmp;
        p2=p2->next;
    }
}

//链表求两个集合A,B的并集A=AUB
void linklist_union(linklist &A,linklist B){
    //求A的最后一个节点的地址pre,最后用rear11表示
    node *rear11=A->next;
    node *pre=A;
    while(rear11){
        pre=pre->next;
        rear11=rear11->next;
    }
    rear11=pre;

    node *rear2=B->next;
    while(rear2){
        bool flag=false;    
        node *rear1=A->next;
        while(rear1){
            if(rear1->data==rear2->data){
                flag=true;
                break;
            }
            rear1=rear1->next;
        }
        if(!flag){
            node *tmp=new node;
            if(tmp==nullptr)error_message("内存分配失败");
            tmp->next=nullptr;
            tmp->data=rear2->data;
            rear11->next=tmp;
            rear11=tmp;
        }
        rear2=rear2->next;
    }
}

//把链表改成单循环链表
void to_circle_linklist(linklist &L){
    node *p=L;
    while(p->next!=nullptr){
        p=p->next;
    }
    p->next=L;
}

//合并两个链表
void linklist_combine(linklist &L1,linklist &L2){
    node *p=L1;
    while(p->next!=nullptr){
        p=p->next;
    }
    p->next=L2->next;
}


链表.cpp
//下面是一个链表基本操作的测试用的程序

//下面是一个链表基本操作的测试用的程序

#include<iostream>
#include"链表.h"

using namespace std;



int main()
{
    freopen("input.txt","r",stdin);

    linklist list1=nullptr;
    linklist list2=nullptr;
    linklist list3=nullptr;
    linklist list4=nullptr;
    dlinklist list5=nullptr;

    //头插法创建一个长度是5的链表:1,2,3,4,5
    cout<<"下面头插法创建链表list1,请输入5,4,3,2,1"<<endl;
    create_linklist1(list1,5);
    cout<<"list1: ";
    linklist_traverse(list1);//输出链表


    //尾插法创建一个长度为5的链表:1,2,3,3,3,4,5
    cout<<"下面尾插法创建链表list2,请输入1,2,3,3,3,4,5"<<endl;
    create_linklist2(list2,7);
    cout<<"list2: ";
    linklist_traverse(list2);
    //尾插法创建链表list3: 7,8,9
    create_linklist2(list3,3);
    cout<<"list3: ";
    linklist_traverse(list3);
    cout<<endl;

    //求链表长度
    cout<<"list1的长度是"<<linklist_length(list1)<<endl;

    //查找
    elemtype e1;
    get_elem(list1,5,e1);
    cout<<"list1中第5个元素是"<<e1<<endl;
    cout<<endl;

    cout<<"list2中第1个3的位置是"<<locate_elem(list2,3)<<endl;
    cout<<"list2中与3相等的节点的个数是"<<e_num(list2,3)<<endl;

    //插入
    cout<<"list2中第4个节点之前插入6后的list2: "<<endl;
    linklist_insert(list2,4,6);
    linklist_traverse(list2);

    //逆置链表
    cout<<"list2逆置后:";
    linklist_reverse(list2);
    linklist_traverse(list2);

    //删除操作
    elemtype e2;
    linklist_delete(list2,2,e2);
    cout<<"删除list2的第2个元素"<<e2<<"后,list2: ";
    linklist_traverse(list2);
    cout<<endl;

    //两个有序表合并成一个有序表
    cout<<"list1和list3合并为list4: ";
    linklist_merge(list1,list3,list4);
    linklist_traverse(list4);
    cout<<endl;

    //求两个集合A,B的并集A(A=AUB)
    linklist_union(list1,list3);
    cout<<"list1,list3两个集合的并集为list1(list1 U list3):";
    linklist_traverse(list1);

    cout<<endl;
    cout<<"***************************************************************************"<<endl;
    cout<<"目前四个链表如下"<<endl;
    cout<<"list1:";linklist_traverse(list1);
    cout<<"list2:";linklist_traverse(list2);
    cout<<"list3:";linklist_traverse(list3);
    cout<<"list4:";linklist_traverse(list4);
    cout<<endl;

    //把list1,list2改成单循环链表,并合并成一个链表
    cout<<"list1,list2合并成list1"<<endl;
    linklist_combine(list1,list2);
    cout<<"list1:";linklist_traverse(list1);
    cout<<endl;

    //建立双向链表list5:12,13,14,15,16,17
    cout<<"创建双向循环链表list5"<<endl;
    create_dlinklist2(list5,6);
    cout<<"list5:";
    dlinklist_traverse(list5,6);
    cout<<endl;

    //双向循环链表list5的第3个元素之前插入666
    cout<<"list5的第3个元素之前插入666"<<endl;
    dlinklist_insert(list5,3,666);
    cout<<"list5: ";
    dlinklist_traverse(list5,7);
    cout<<endl;

    //双向循环链表list5删除第4个元素
    elemtype e3;
    dlinklist_delete(list5,4,e3);
    cout<<"删除list5中的第4个元素"<<e3<<"后,list5: ";
    dlinklist_traverse(list5,6);
    cout<<endl;

    //删除list1中偶数序号结点
    cout<<"删除偶数序号结点后,list1: ";
    linklist_delete_even(list1);
    linklist_traverse(list1);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值