C语言实现个人通讯录(功能优化)-2

简介: C语言实现个人通讯录(功能优化)

C语言实现个人通讯录(功能优化)-1

https://developer.aliyun.com/article/1536733


3.6 通讯录的排序:

这个功能实现就相对于前面的功能来说就有意思多了,来听我细细道来:


  • 排序算法有八种,各种排序都是很不错的思路,比如被用于教学的冒泡排序,简单易懂,思想也贴切排序思想,所以常常用来教学初级;(具体八大排序算法,之后也会写成博客)
  • 这里我就选用八大排序最舒服的快排,为什么选用快排呢,当然是快咯,哈哈,但快排也在这里有一些缺陷,如果数据很少,或者有很多都是顺序输入,快排就有一点点吃亏,没事儿----会优化!!!
  • 先来介绍一下快排的思路吧,快排最开始是Hoare大佬提出来的思路如图: cdfe875b08184cac82ce0986b910dfd1.gif


这就是最开始Hoare大佬的快排思路:

  • 1.先定一个key值,把比key小的放key的以边,把比key大的放一边,这样key就找到了正确位置,这就是一趟的思路,不断二分,就可以排序了。
  • 2.不断二分,可递归,可不用递归,这里我就只是说一下递归方式。
void Swap( int* left,int* right)
{
  int t = *left;
  *left = *right;
  *right = t;
}
void Hoare_QuickSort(int* a, int left, int right)
{
//当二分到key值的一边只有一个数,或者没有时,便递归结束
  if (left >= right)
    return;
    
  int end = right, begin = left;
  int keyi = left;//这里表示的是key的下标索引
  while (left < right)
  {
    //左边做key,右边先走,可以保证相遇位置比key更小
    //right找小找到和找不到:
    //找到:left没有找到大,直到相遇
    //没找到:直接和left相遇,直接找到keyi值
    while (left<right&&a[right] >= a[keyi])//right找小停下
      right--;

    while (left<right&&a[left] <= a[keyi])//left找大(保证相遇小于key)
      left++;
    Swap( &a[left],&a [right]);//交换两者,分配
  }
  //最后相遇位置便是key的位置:
  Swap(&a[left], &a[keyi]);
  keyi = left;
  //key左边数组的初末索引:begin,keyi-1
  Hoare_QuickSort(a, begin, keyi - 1);
  //key右边数组的初末索引:keyi+1,end
  Hoare_QuickSort(a, keyi + 1, end);
}

当然Hoare大佬提出的版本肯定是存在一定缺陷的,需要优化,但是这种思想真的厉害!

这里直接给出时间复杂度:O(NlgN)~O(N*N)


  • 缺陷: 1.当所需要排的数列是顺序或者逆序时,快排时间复杂度是最大N的平方,严重影响快排的速度。2.快排在对数据少,并且部分具有一定顺序的排序并不是很完美。3.Hoare大佬的快排思路难以理解,思路理解困难。

对于上述缺陷我这里就不过度介绍了,但的确有优化方式(我会在后续的八大排序中介绍)在通讯录排序中用较优秀的方式来实现(这里就是和库里排序函数实现相近了):


void Swap(PeoInfo* left, PeoInfo* right)
{
  PeoInfo t = *left;
  *left = *right;
  *right = t;
}

int GerMidNumi(PeoInfo* a, int left, int right)
{
  int mid = (right + left) / 2;

  if (strcmp(a[left].name, a[mid].name) > 0)
  {
    if (strcmp(a[mid].name, a[right].name) > 0)
    {
      return mid;
    }
    else if (strcmp(a[left].name, a[right].name) < 0)
    {
      return left;
    }
    else
    {
      return right;
    }
  }
  else
  {
    if (strcmp(a[left].name, a[right].name) > 0)
    {
      return left;
    }
    else if (strcmp(a[mid].name, a[right].name) < 0)
    {
      return mid;
    }
    else
    {
      return right;
    }
  }
}

void  DP_QuickSort(PeoInfo* a, int left, int right)
{
  int end = right, begin = left;
  if (left >= right)
    return;
  //小区间优化:
  if ((right - left + 1) > 10)
  {
    //方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
    int midi = GerMidNumi(a, left, right);
    if (midi != left)
      Swap(&a[left], &a[midi]);

    int prev = left;
    int cur = prev + 1;
    int keyi = left;

    while (cur <= right)
    {
      if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
        Swap(&a[cur], &a[prev]);
      cur++;
    }
    Swap(&a[prev], &a[keyi]);
    keyi = prev;

    DP_QuickSort(a, begin, keyi - 1);
    DP_QuickSort(a, keyi + 1, end);
  }
  else
  {
    InsertSort(a, right - left + 1);
  }
}

void InsertSort(PeoInfo* a, int n)
{
  for (int i = 1; i < n; i++)
  {
    int end = i - 1;
    PeoInfo tmp = a[i];
    // 将tmp插入到[0,end]区间中,保持有序
    while (end >= 0)
    {
      if (strcmp(tmp.name, a[end].name) < 0)
      {
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = tmp;
  }
}

运行效果:

1fc44db07f565dd3433b41d14c0f00d8_092ab7206c0d43ea93fa1d2060ccc0a0.png


这里很有趣,但在这个部分就不过度介绍了,在后续博客会有详细介绍哈!


3.7 文件导入和导出功能:

我们当前所写的代码都是在内存里写的,一旦关闭数据便会清除,所以需要把数据导入到本地磁盘中进行保存,这里就需要文件相关知识了。知识掌握了,就十分简单了!


  • 本地导入内存:
void LondContact(Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
  if (NULL == pf)
  {
    perror("LondContact error");
  }
  else
  {
    int i = 0;
    PeoInfo tmp = { 0 };
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))
    {
      CapacityContact(pc);
      pc->data[i] = tmp;
      pc->sz++;
      i++;
    }
    fclose(pf);
    pf = NULL;
  }
}
  • 内存存入本地:
void SaveContact(const Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
  if (NULL == pf)
  {
    perror("SaveContact error");
  }
  else
  {
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
      fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    printf("保存成功\n");
  }
}

这就实现了通讯录的基本功能喽


3.8 分组打印:

这里我的通讯录是把分组定义为联系人的属性了的,所以只需要按照分组查找打印即可:


  void SearchByClass(const Contact* ps)
{
  {
    int i = 0;
    char class[CLASS_MAX];
    int flag = 0;
    int k = 1;
    printf("请输入需要查找联系人的组别:");
    scanf("%s", class);
    for (i = 0; i < ps->sz; i++)
    {
      if (strcmp(class, ps->data[i].class) == 0)
      {
        flag = 1;
        if (k == 1)
        {
          printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
          k--;
        }
        printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
          ps->data[i].name,
          ps->data[i].age,
          ps->data[i].sex,
          ps->data[i].address,
          ps->data[i].phone,
          ps->data[i].class);
      }
    }
    if (flag)
    {
      return;
    }
    else
    {
      printf("无法找到该联系人信息\n");
    }
  }
}


3.9 隐蔽空间的实现:

  • 这里的思路就是另外开辟本地文件,作为存储空间,但要注意的是,调用隐蔽空间时,切记先保存通讯录原本空间,并且退出(销毁)。再打开隐蔽空间的文件,就相当于实现一个小的通讯录,功能可照搬所以就不过多介绍。
  • 只介绍一下进入空间时的一些优化吧,比如ShowHide()函数,看似只是加载界面,其实他还可以实现清除屏幕(调用windows自带的cls)原先信息,做到更舒服的访问。代码如下:
void ShowHide()
{
  char arr1[] = "Welcome to Hide Room !!!";
  char arr2[] = "########################";

  int left = 0;
  int right = strlen(arr1) - 1;

  while (left <= right)
  {
    arr2[left] = arr1[left];
    arr2[right] = arr1[right];
    printf("%s\n", arr2);
    Sleep(1000);
    //清屏
    system("cls");
    left++;
    right--;
  }
  printf("%s\n", arr1);
}
  • 输入密码进入bool EncryptionContact()函数,这个函数还有太多可优化的地方:比如三次密码输入失败,24小时重试,这里用C语言就不方便了,可以用linux实现(后续会出相关博客)这里只能打印表示,还有就是密码的修改,这里我想的是还可以实现一个管理程序(哈哈,写博客想着想着就去实现了个,现在和大家分享!!!)
void Administrators(char* password)
{
  char newpassword[20];
  printf("请输入修改密码》:");
  scanf("%s", newpassword);
  strcpy(password, newpassword);
  printf("修改成功\n");
}

bool EncryptionContact()
{
  int i = 0;
  char password[20] = { 0 };
  char insure[20] = { "123456" };
//打开一个文件夹用来记录空间密码:
  FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
  if (NULL == pf1)
  {
    perror("password1 error");
  }
  else
  {
    char tmp[20] = { 0 };
    fread(&tmp, 20, 1, pf1);
    strcpy(insure, tmp);
    fclose(pf1);
    pf1 = NULL;
  }
//判断的主要函数:
  printf("请输入进入密码》:");
  for (i = 0; i < 3; i++)
  {
    scanf("%s", password);
    if (0 == strcmp(password, insure))
    {
      return true;
    }
    else if (0==strcmp(password,"管理员入口"))
    {
    //进入管理员系统进行密码修改
      Administrators(insure);
    //存入密码文件中
      FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
      if (NULL == pf2)
      {
        perror("password2 error");
      }
      else
      {
        fwrite(insure, 20, 1, pf2);
        fclose(pf2);
        pf2 = NULL;
        printf("保存成功\n");
      }
      printf("请输入进入密码》:");
    }
    else
    {
      printf("第%d次密码输入错误\n", i + 1);
      if (i < 2)
        printf("请重新输入》:");
    }
  }
  //linux操作系统实现
  printf("密码输入三次错误!请在24小时后重试\n");
  return false;
}

运行效果:

51ef82c8be39392ee0da248ca9122d3f_539d0879214942d6bb574b86e2e61bf5.png

0df86f41180968f71ce776d28fad0225_ac185cdb1a3f42428cd82b468db4a8b0.png


这里可以形成一个对比,就是代码没有封装可读性就很差,这里可以把写入和写出封装成函数。这里关于隐蔽空间其他功能大致相同就不过多介绍了。


Contact.c完整代码:


#include"Contact.h"

void mune()
{
  printf("*******************************************************\n");
  printf("********1.SearchByName    2.SearchByAge ***************\n");
  printf("********3.SearchBySex     4.SearchByAddr   ************\n");
  printf("********5.SearchByPhone   6.SearchByclass  ************\n");
  printf("*******************  0.exit  **************************\n");
  printf("*******************************************************\n");
}
void mune1()
{
  printf("**************************************\n");
  printf("********1.ADD    2.DEL ***************\n");
  printf("********3.SEARCH 4.MODIFY ************\n");
  printf("********5.SHOW   6.SORT   ************\n");
  printf("********0.EXIT            ************\n");

}

void func(Contact* pc)
{
  int input;
  mune1();
  do {
    printf("请输入选项>:");
    scanf("%d", &input);
    //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
    //若输入为0,则判断为FALSE,跳出循环,退出通讯录
    switch (input)
    {
    case ADD:
      AddContact(pc);
      break;
    case DEL:
      DelContact(pc);
      break;
    case SEARCH:
      SearchContact(pc);
      break;
    case MODIFY:
      ModifyContact(pc);
      break;
    case SHOW:
      PrintContact(pc);
      break;
    case SORT:
      SortContact(pc);
      break;
    case EXIT:
      //保存到文件中
      Hide_SaveContact(pc);
      //销毁通讯录空间
      DestroyContact(pc);
      printf("退出通讯录\n");
      break;
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  } while (input);

  return;
}

void LondContact(Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
  if (NULL == pf)
  {
    perror("LondContact error");
  }
  else
  {
    int i = 0;
    PeoInfo tmp = { 0 };
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))
    {
      CapacityContact(pc);
      pc->data[i] = tmp;
      pc->sz++;
      i++;
    }
    fclose(pf);
    pf = NULL;
  }
}

//主要用于函数的实现操作,功能实现处
//动态内存处理
void InitContact(Contact* pc)
{
  assert(pc);
  pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
  if (pc->data == NULL)
  {
    perror("malloc error");
  }
  pc->sz = 0;
  pc->capacity = INIT_MAX;

  //读取文件
  LondContact(pc);
}

void CapacityContact(Contact* pc)
{
  if (pc->sz == pc->capacity)
  {
    pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2);
    if (pc->data == NULL)
    {
      perror("realloc error");
    }
    pc->capacity = pc->capacity * 2;
    printf("扩容成功\n");
  }
}

void AddContact(Contact* pc)
{
  assert(pc);
  //自动扩容
  CapacityContact(pc);

  printf("请输入联系人名字:");
  scanf("%s", pc->data[pc->sz].name);
  printf("请输入联系人年龄:");
  scanf("%d", &(pc->data[pc->sz].age));
  printf("请输入联系人性别:");
  scanf("%s", pc->data[pc->sz].sex);
  printf("请输入联系人地址:");
  scanf("%s", pc->data[pc->sz].address);
  printf("请输入联系人电话:");
  scanf("%s", pc->data[pc->sz].phone);
  printf("请设置联系人组别:");
  scanf("%s", pc->data[pc->sz].class);

  pc->sz++;
  return;
}

void DelContact(Contact* pc)
{
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录中无对象可操作!请先增加!");
    mune1();
    return;
  }
  int ret = SearchByName(pc);
  if (ret == -1)
  {
    printf("删除失败请重新操作!");
    mune1();
    return;
  }
  int i = ret;
  for (i = ret; i < pc->sz - 1; i++)
  {
    pc->data[i] = pc->data[i + 1];

  }

  printf("删除成功!\n");
  //这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间
  pc->sz--;
  mune1();
}

int SearchContact(const Contact* pc)
{
  assert(pc);
  //多种方式查找:
  mune();
  int input;
  int ret = -1;
  do {
    //选项的输入
    printf("请输入选项>:");
    scanf("%d", &input);
    //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
    //若输入为0,则判断为FALSE,跳出循环,
    switch (input)
    {
    case S_ByName:
      ret = SearchByName(pc);
      break;
    case S_ByAge:
      SearchByAge(pc);
      break;
    case S_BySex:
      SearchBySex(pc);
      break;
    case S_ByAddr:
      SearchByAddr(pc);
      break;
    case S_ByPhone:
      ret = SearchByPhone(pc);
      break;
    case S_ByClass:
      SearchByClass(pc);
      break;
    case EXIT:
      printf("查找完成,已经返回上一级\n");
      mune1();
      break;
    default:
      printf("该查找方式还待开发哦,请重新输入\n");
      break;
    }
  } while (input);
  return ret;
}

  int SearchByName(const Contact* ps)
{
  int i = 0;
  char name[NAME_MAX];
  int k = 1;
  printf("请输入需要的联系人名字:");
  scanf("%s", name);
  for (i = 0; i < ps->sz; i++)
  {
    if (strcmp(name, ps->data[i].name) == 0)
    {
      //暂时不考虑重名
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }

      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);

      return i;
    }
  }
  printf("无法找到该联系人信息\n");
  return -1;
}

  void SearchByAge(const Contact* ps)
{
  int i = 0;
  int age;
  int flag = 0;
  int k = 1;
  printf("请输入需要查找联系人的年龄:");
  scanf("%d", &age);
  for (i = 0; i < ps->sz; i++)
  {
    if (age == ps->data[i].age)
    {
      flag = 1;
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }

      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);
    }
  }
  if (flag)
  {
    return;
  }
  else
  {
    printf("无法找到该联系人信息\n");
  }
}

  void SearchBySex(const Contact* ps)
{
  int i = 0;
  char sex[SEX_MAX];
  int flag = 0;
  int k = 1;
  printf("请输入需要查找联系人的性别:");
  scanf("%s", sex);
  for (i = 0; i < ps->sz; i++)
  {
    if (strcmp(sex, ps->data[i].sex) == 0)
    {
      flag = 1;
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }
      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);
    }
  }
  if (flag)
  {
    return;
  }
  else
  {
    printf("无法找到该联系人信息\n");
  }
}

  void SearchByAddr(const Contact* ps)
{
  {
    int i = 0;
    char addr[ADDR_MAX];
    int flag = 0;
    int k = 1;
    printf("请输入需要查找联系人的地址:");
    scanf("%s", addr);
    for (i = 0; i < ps->sz; i++)
    {
      if (strcmp(addr, ps->data[i].address) == 0)
      {
        flag = 1;
        if (k == 1)
        {
          printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
          k--;
        }
        printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
          ps->data[i].name,
          ps->data[i].age,
          ps->data[i].sex,
          ps->data[i].address,
          ps->data[i].phone,
          ps->data[i].class);
      }
    }
    if (flag)
    {
      return;
    }
    else
    {
      printf("无法找到该联系人信息\n");
    }
  }
}

  void SearchByClass(const Contact* ps)
{
  {
    int i = 0;
    char class[CLASS_MAX];
    int flag = 0;
    int k = 1;
    printf("请输入需要查找联系人的组别:");
    scanf("%s", class);
    for (i = 0; i < ps->sz; i++)
    {
      if (strcmp(class, ps->data[i].class) == 0)
      {
        flag = 1;
        if (k == 1)
        {
          printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
          k--;
        }
        printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
          ps->data[i].name,
          ps->data[i].age,
          ps->data[i].sex,
          ps->data[i].address,
          ps->data[i].phone,
          ps->data[i].class);
      }
    }
    if (flag)
    {
      return;
    }
    else
    {
      printf("无法找到该联系人信息\n");
    }
  }
}

  int SearchByPhone(const Contact* ps)
{
  int i = 0;
  char phone[PHONE_MAX];
  int k = 1;
  printf("请输入需要查找联系人电话号码:");
  scanf("%s", phone);
  for (i = 0; i < ps->sz; i++)
  {
    if (strcmp(phone, ps->data[i].phone) == 0)
    {
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }

      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);

      return i;
    }
  }
  printf("无法找到该联系人信息\n");
  return -1;
}

void ModifyContact(Contact* pc)
{
  int ret = -1;
  int i;
  i = SearchByName(pc);
  if (i != ret)
  {
    printf("请输入修改的内容(部分):\n");
    printf("请输入联系人名字:");
    scanf("%s", pc->data[i].name);
    printf("请输入联系人年龄:");
    scanf("%d", &(pc->data[i].age));
    printf("请输入联系人性别:");
    scanf("%s", pc->data[i].sex);
    printf("请输入联系人地址:");
    scanf("%s", pc->data[i].address);
    printf("请输入联系人电话:");
    scanf("%s", pc->data[i].phone);

  }

}

void PrintContact(const Contact* pc)
{
  assert(pc);
  int i = 0;
  printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
  for (i = 0; i < pc->sz; i++)
  {
    printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].address,
      pc->data[i].phone,
      pc->data[i].class);
  }
}

void DestroyContact(Contact* pc)
{
  free(pc->data);
  pc->data = NULL;
  pc->capacity = 0;
  pc->sz = 0;
  pc = NULL;
}

void SaveContact(const Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
  if (NULL == pf)
  {
    perror("SaveContact error");
  }
  else
  {
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
      fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    printf("保存成功\n");
  }
}

void SortContact(const Contact* pc)
{
  assert(pc);

  DP_QuickSort(pc->data, 0, pc->sz - 1);

  printf("排序完成\n");

}

void Swap(PeoInfo* left, PeoInfo* right)
{
  PeoInfo t = *left;
  *left = *right;
  *right = t;
}

int GerMidNumi(PeoInfo* a, int left, int right)
{
  int mid = (right + left) / 2;

  if (strcmp(a[left].name, a[mid].name) > 0)
  {
    if (strcmp(a[mid].name, a[right].name) > 0)
    {
      return mid;
    }
    else if (strcmp(a[left].name, a[right].name) < 0)
    {
      return left;
    }
    else
    {
      return right;
    }
  }
  else
  {
    if (strcmp(a[left].name, a[right].name) > 0)
    {
      return left;
    }
    else if (strcmp(a[mid].name, a[right].name) < 0)
    {
      return mid;
    }
    else
    {
      return right;
    }
  }
}

void  DP_QuickSort(PeoInfo* a, int left, int right)
{
  int end = right, begin = left;
  if (left >= right)
    return;
  //小区间优化:
  if ((right - left + 1) > 10)
  {
    //方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
    int midi = GerMidNumi(a, left, right);
    if (midi != left)
      Swap(&a[left], &a[midi]);

    int prev = left;
    int cur = prev + 1;
    int keyi = left;

    while (cur <= right)
    {
      if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
        Swap(&a[cur], &a[prev]);
      cur++;
    }
    Swap(&a[prev], &a[keyi]);
    keyi = prev;

    DP_QuickSort(a, begin, keyi - 1);
    DP_QuickSort(a, keyi + 1, end);
  }
  else
  {
    InsertSort(a, right - left + 1);
  }
}

void InsertSort(PeoInfo* a, int n)
{
  for (int i = 1; i < n; i++)
  {
    int end = i - 1;
    PeoInfo tmp = a[i];
    // 将tmp插入到[0,end]区间中,保持有序
    while (end >= 0)
    {
      if (strcmp(tmp.name, a[end].name) < 0)
      {
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = tmp;
  }
}

void  Hide_InitContact(Contact* pc)
{
  assert(pc);
  pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
  if (pc->data == NULL)
  {
    perror("Hide_malloc error");
  }
  pc->sz = 0;
  pc->capacity = INIT_MAX;

  //读取文件
  Hide_LondContact(pc);
}

void Hide_LondContact(Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "rb");
  if (NULL == pf)
  {
    perror("Hide_LondContact error");
  }
  else
  {
    int i = 0;
    PeoInfo tmp = { 0 };
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))
    {
      CapacityContact(pc);
      pc->data[i] = tmp;
      pc->sz++;
      i++;
    }
    fclose(pf);
    pf = NULL;
  }
}

void ShowHide()
{
  char arr1[] = "Welcome to Hide Room !!!";
  char arr2[] = "########################";

  int left = 0;
  int right = strlen(arr1) - 1;

  while (left <= right)
  {
    arr2[left] = arr1[left];
    arr2[right] = arr1[right];
    printf("%s\n", arr2);
    Sleep(1000);
    system("cls");
    left++;
    right--;
  }
  printf("%s\n", arr1);
}

void Administrators(char* password)
{
  char newpassword[20];
  printf("请输入修改密码》:");
  scanf("%s", newpassword);
  strcpy(password, newpassword);
  printf("修改成功\n");
}

bool EncryptionContact()
{
  int i = 0;
  char password[20] = { 0 };
  char insure[20] = { "123456" };

  FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
  if (NULL == pf1)
  {
    perror("password1 error");
  }
  else
  {
    char tmp[20] = { 0 };
    fread(&tmp, 20, 1, pf1);
    strcpy(insure, tmp);
    fclose(pf1);
    pf1 = NULL;
  }

  printf("请输入进入密码》:");
  for (i = 0; i < 3; i++)
  {
    scanf("%s", password);
    if (0 == strcmp(password, insure))
    {
      return true;
    }
    else if (0==strcmp(password,"管理员入口"))
    {
      Administrators(insure);
      FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
      if (NULL == pf2)
      {
        perror("password2 error");
      }
      else
      {
        fwrite(insure, 20, 1, pf2);
        fclose(pf2);
        pf2 = NULL;
        printf("保存成功\n");
      }
      printf("请输入进入密码》:");
    }
    else
    {
      printf("第%d次密码输入错误\n", i + 1);
      if (i < 2)
        printf("请重新输入》:");
    }
  }
  //linux操作系统实现
  printf("密码输入三次错误!请在24小时后重试\n");
  return false;

}

void Hide_SaveContact(const Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "wb");
  if (NULL == pf)
  {
    perror("Hide_SaveContact error");
  }
  else
  {
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
      fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    printf("保存成功\n");
  }
}

4.代码缺陷,以及优化:

4.1 内存泄漏:

内存泄漏是必须注意的,这里开始malloc了空间,如果没有释放则会影响项目的速度,举个例子:


  • 这里是一个死循环,用来模拟长期在线的服务器,当出现内存泄漏问题会有什么后果:

c9fb5d169f2f8d09096603ac17abdc31_98ca36b7554f4c2084793b491d3c6945.png

  • 开始运行代码:

47f1c78933c097d10a5511220c7b0b10_8d12e19edb5e41f2b07107ffae11aa2b.png

可以注意vs2019所占得内存以及多了这么多,这些没用的空间,会影响项目整体性能,当然在这里只需要把黑匣子关掉,就马上恢复了,这是结束的时候自动释放了。如果未来我们从事的是24小时在线的服务器(比如各种app),出现这种内存泄漏可是及其危险的。所以我们需要手动释放。

void DestroyContact(Contact* pc)
{
  free(pc->data);
  pc->data = NULL;
  pc->capacity = 0;
  pc->sz = 0;
  pc = NULL;
}

代码简单不累,相当实惠哈哈,所以这是要养成的习惯,在申请空间后一定记住手动free多余空间;


4.2 代码可读性维护:

  • 有句流传江湖的话:程序员写完代码,只有自己和上帝认识!
  • 在项目合作过程中的,代码可读性十分重要
  • 比如函数命名、Switch语句的case选项可以枚举代替、以及增加必要注释。增加代码可读性,这里就举case这个例子

05c5afd80876a6819a31a04d9ade1f02_59d319d2d511416e897646df58c10dc4.png

是不是还是有些区别的呢?


4.3 代码的可调式性:

我们往往可以发现我们在写类似“项目”的时候,发现代码一长,是真的难调,一调就是一天,所以我们就要用一些技巧:


  • 1.善用const关键字,对于一些参数无需修改的函数,大胆加上这个关键字,比如通讯录的打印函数
  • 2.会用assert()函数,使用函数我们通常成为暴力检查,这个函数会让你的调试找到方向,明白什么地方错了,便于调试。
  • 3.perror()函数也是如此,若不清楚可以自行查询。

PS:好久没写博客咯,后续会抓紧的哈哈!美图献上(夹带私货),一起加油!

相关文章
|
10天前
|
存储 C语言 索引
C语言实现个人通讯录(功能优化)-1
C语言实现个人通讯录(功能优化)
C语言实现个人通讯录(功能优化)-1
|
17天前
|
C语言
C语言学习记录——通讯录(静态内存)
C语言学习记录——通讯录(静态内存)
14 2
|
27天前
|
存储 C语言
C语言实现通讯录
C语言实现通讯录
21 2
|
17天前
|
存储 C语言
C语言学习记录——通讯录(动态内存)
C语言学习记录——通讯录(动态内存)
13 0
|
27天前
|
存储 C语言
动态+静态+文件操作 C语言实现通讯录
通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
24 0
|
27天前
|
存储 文件存储
升级版通讯录(C语言版)
升级版通讯录(C语言版)
20 0
|
2天前
|
C语言
C语言---函数---请输入乘法口诀表的行,来打印几几乘法表
C语言---函数---请输入乘法口诀表的行,来打印几几乘法表
|
2天前
|
C语言
C语言--函数递归与迭代
C语言--函数递归与迭代
|
2天前
|
C语言 C++
C语言----C语言内存函数
C语言----C语言内存函数
|
2天前
|
C语言
C语言----字符函数和字符串函数(4)
C语言----字符函数和字符串函数